Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » Sort rows in the grid programmatically Collapse All
Subject Author Date
Offer Har Sep 17, 2007 - 7:34 AM

Dear Support,

I have a grid which is sorted.
When new rows are added to the grid, I would like them to be added at the correct location according to the sorting order (the user clicks column header to set the sort order - default behavior).

What I do, is add the new rows at the bottom of the grid, and then I want to re-sort it according to the current sort column and order.

I read the FAQ about this GridSortOrderSetup function, but I need to know what is the current sort column and order, and I have no idea how to extract this data from my grid.

Technical Support Sep 20, 2007 - 5:14 AM

You should not remove DYNAMIC_DOWNCAST but you can replace it with STATIC_DOWNCAST if you are sure all the cells in the column are of the the same type. If STATIC_DOWNCAST generates assertions, your grid cell’s code is not safe. We believe STATIC_DOWNCAST will raise assertions. The grid cell classes require DECLARE_SERIAL and IMPLEMENT_SERIAL instead of DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE. This should be the main problem with your short version of grid cell class.

Technical Support Sep 19, 2007 - 12:47 PM

We have just checked your class by using Prof-UIS_Controls sample ans found out that the Compare method is called and the other cell after downcasting had the valid type CExtGridCellReadOnlyNumber. So, we cannot confirm this problem. Would you reproduce the problem using any of our sample and send it to us?

Offer Har Sep 19, 2007 - 1:21 PM

Dear Support,

I removed the DYNAMIC_DOWNCAST and it seems to work fine.
I guess the problem lies somewhere in this piece of code:

	CExtGridCellReadOnlyNumber * pCell =
		DYNAMIC_DOWNCAST(
		CExtGridCellReadOnlyNumber,
		( const_cast < CExtGridCell * > ( &other ) )
		);

I changed it to:
CExtGridCellReadOnlyNumber * pCell = (CExtGridCellReadOnlyNumber*)(&other)

And all is well - sorting is done as expected.
Any ideas?

Best Regards,
Ron.

Technical Support Sep 17, 2007 - 8:46 AM

You can get information about the current sorting using the CExtGridWnd::GridSortOrderGet() method. But it seems you do not need this method. You should simply invoke the following code after adding one or more new rows/columns at any location inside the grid:

CExtGridWnd & wndGrid = . . .
CExtGridDataProvider & _DataProvider = wndGrid.OnGridQueryDataProvider();
      _DataProvider.SortOrderUpdate( true, &wndGrid );
      _DataProvider.SortOrderUpdate( false, &wndGrid );

Offer Har Sep 17, 2007 - 9:37 AM

Thanks - problem solved...

I have another problem with sorting - I need to sort some columns accoring to their integer value, and not the default lexicographic sorting.
How can I add my custom/integer sorting to a column?

Regards,
Ron.

Technical Support Sep 18, 2007 - 3:42 AM

When data is sorted in the grid, the CExtGridCell::Compare() virtual method is called in order to compare each cell pair in each sorted column. Please note that different cell classes have different implementations of this method. We guess you are using some simple text cell class like CExtGridCellString in the column with numeric data. It seems you should use some other cell type for this column (e.g. CExtGridCellNumber).

Offer Har Sep 18, 2007 - 4:57 AM

Dear Support,

I format my text (number) in a very specific way i add comma, and unit, so using CExtGridCellNumber is not a good option for me.
If I understand correctly, I should derive my cell, say CExtCellRange, which will hold the number I need to compare, and add the virtual Compare function?

Technical Support Sep 18, 2007 - 11:16 AM

Your grid cell class may look like as follows:

class CRangeCellForRon : public CExtGridCellEx
{
public:
      typedef int some_type_t;

      some_type_t m_rangeBegin;
      some_type_t m_rangeEnd;

      DECLARE_SERIAL( CRangeCellForRon );
      IMPLEMENT_ExtGridCell_Clone( CRangeCellForRon, CExtGridCellEx );

      CRangeCellForRon( CExtGridDataProvider * pDataProvider = NULL )
            : CExtGridCellEx( pDataProvider )
            , m_rangeBegin( 0 )
            , m_rangeEnd( 0 )
      {
      }
      CRangeCellForRon( const CRangeCellForRon & other )
            : CExtGridCellEx( other )
      {
      }
      virtual ~CRangeCellForRon()
      {
      }

      bool IsEmpty() const
      {
            ASSERT_VALID( this );
            return false;
      }
      virtual void Empty()
      {
            CExtGridCellEx::Empty();
            m_rangeBegin = 0;
            m_rangeEnd = 0;
      }
      virtual void Serialize( CArchive & ar )
      {
            CExtGridCellEx::Serialize( ar );
            if( ar.IsStoring() )
            {
                  ar << m_rangeBegin;
                  ar << m_rangeEnd;
            }
            else
            {
                  ar >> m_rangeBegin;
                  ar >> m_rangeEnd;
            }
      }
      virtual void Assign( const CExtGridCell & other )
      {
            ASSERT_VALID( this );
            CExtGridCellEx::Assign( other );
            CRangeCellForRon * pCell =
                  DYNAMIC_DOWNCAST(
                        CRangeCellForRon,
                        ( const_cast < CExtGridCell * > ( &other ) )
                        );
            if( pCell != NULL )
            {
                  // copy cell
                  m_rangeBegin = pCell->m_rangeBegin;
                  m_rangeEnd = pCell->m_rangeEnd;
            }
            else
            {
                  // clear cell
                  m_rangeBegin = 0;
                  m_rangeEnd = 0;
            }
      }
      virtual int Compare(
            const CExtGridCell & other,
            DWORD dwStyleMask = __EGCS_COMPARE_MASK,
            DWORD dwStyleExMask = __EGCS_EX_COMPARE_MASK
            ) const
      {
            ASSERT_VALID( this );
            CRangeCellForRon * pCell =
                  DYNAMIC_DOWNCAST(
                        CRangeCellForRon,
                        ( const_cast < CExtGridCell * > ( &other ) )
                        );
            if( pCell == NULL )
                  return CExtGridCellEx::Compare( other, dwStyleMask, dwStyleExMask );
            if( m_rangeBegin < pCell->m_rangeBegin )
                  return -1;
            if( m_rangeBegin > pCell->m_rangeBegin )
                  return 1;
            if( m_rangeEnd < pCell->m_rangeEnd )
                  return -1;
            if( m_rangeEnd > pCell->m_rangeEnd )
                  return 1;
            return CExtGridCellEx::Compare( other, dwStyleMask, dwStyleExMask );
      }
      virtual void TextGet( CExtSafeString & strCopy ) const
      {
            ASSERT_VALID( this );
            if(         (GetStyleEx()&__EGCS_EX_UNDEFINED_ROLE) != 0 
                  ||    IsEmpty()
                  )
            {
                  strCopy = _T("");
                  return;
            }
            strCopy.Format( _T("%d - %d"), int(m_rangeBegin), int(m_rangeEnd) );
      }
      virtual void TextSet(
            __EXT_MFC_SAFE_LPCTSTR str = __EXT_MFC_SAFE_LPCTSTR(NULL), // empty text
            bool bAllowChangeDataType = false
            )
      {
            ASSERT_VALID( this );
            bAllowChangeDataType; 
            Empty();
            _stscanf( LPCTSTR(str), _T("%d - %d"), (int*)(&m_rangeBegin), (int*)(&m_rangeEnd)  );
      }
      virtual HRESULT OnParseText( __EXT_MFC_SAFE_LPCTSTR sText ) const
      {
            ASSERT_VALID( this );
            ASSERT( sText != NULL );
            if( sText == NULL )
                  return E_INVALIDARG;
            int _rangeBegin = 0, _rangeEnd = 0;
            if( _stscanf( LPCTSTR(sText), _T("%d - %d"), &_rangeBegin, &_rangeEnd  ) != 2 )
                  return E_FAIL;
            return S_OK;
      }
};

// this line of code should be placed at the beginning of .CPP file before the definition of
// MFC’s debug version of the new operator
IMPLEMENT_SERIAL( CRangeCellForRon, CExtGridCellEx, VERSIONABLE_SCHEMA|1 );

Offer Har Sep 18, 2007 - 4:50 PM

Dear Support,

Thanks for the explanation.
I tried to implement the proposed solution, removing items I don’t need, and ended up with this class:

In the .h file:

class CExtGridCellReadOnlyNumber : public CExtGridCellString
{
	double m_dVal;

public:
	DECLARE_DYNCREATE( CExtGridCellReadOnlyNumber );
	IMPLEMENT_ExtGridCell_Clone( CExtGridCellReadOnlyNumber, CExtGridCellString );

	CExtGridCellReadOnlyNumber(CExtGridDataProvider * pDP = NULL) 
		: CExtGridCellString(pDP)
		, m_dVal(0.0)
	{
		ModifyStyle(__EGCS_NO_INPLACE_CONTROL|__EGCS_TEXT_ELLIPSIS );
	}

	virtual int Compare(
		const CExtGridCell & other,
		DWORD dwStyleMask = __EGCS_COMPARE_MASK,
		DWORD dwStyleExMask = __EGCS_EX_COMPARE_MASK
		) const;

	double GetVal() { return m_dVal; }
	void SetVal(double dVal);

	virtual CString ToString();
};


In the .cpp:
IMPLEMENT_DYNCREATE(CExtGridCellReadOnlyNumber, CExtGridCellString);

void CExtGridCellReadOnlyNumber::SetVal(double dVal)
{
	m_dVal = dVal;
	TextSet(ToString());
}

CString CExtGridCellReadOnlyNumber::ToString()
{
	CString str;
	str.Format("%.0f", m_dVal);
	return str;
}

int CExtGridCellReadOnlyNumber::Compare(const CExtGridCell& other, DWORD dwStyleMask, DWORD dwStyleExMask) const
{
	ASSERT_VALID( this );
	CExtGridCellReadOnlyNumber * pCell =
		DYNAMIC_DOWNCAST(
		CExtGridCellReadOnlyNumber,
		( const_cast < CExtGridCell * > ( &other ) )
		);
	if( pCell == NULL )
		return CExtGridCellEx::Compare( other, dwStyleMask, dwStyleExMask );

	if( m_dVal < pCell->GetVal())
		return -1;
	if( m_dVal > pCell->GetVal() )
		return 1;

	return CExtGridCellEx::Compare( other, dwStyleMask, dwStyleExMask );
}


I have a derived class:
class CRangeCell : public CExtGridCellReadOnlyNumber
{
public:
	DECLARE_DYNCREATE( CRangeCell );
	IMPLEMENT_ExtGridCell_Clone( CRangeCell, CExtGridCellReadOnlyNumber );
	CRangeCell(CExtGridDataProvider * pDP = NULL) : CExtGridCellReadOnlyNumber(pDP) {}

	virtual CString ToString() { return UIUtils::ToStringWith1000Comma(Convert::MeterToYard(GetVal()))+" Y"; }
};


and of-course in the .cpp the IMPLEMENT_DYNCREATE.

All is well, the Compare function is called, but the other cell that it gets as a parameter is not of the right type, so the downcast fails, and my numeric comparing code is never reached.

What is the problem?

Thanks,
Ron.