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 » CExtMDP::SwapDroppedSeries - assertion Collapse All
Subject Author Date
Suhai Gyorgy Jan 11, 2008 - 4:02 AM

Dear Support,

We have a grid with a method for moving rows up/down. It is as follows:

void CMyGridWnd::MoveSelRowByOne(bool bUp)
{
	ASSERT_VALID(this);
	LONG lCurSel = SelectionGetFirstRowInColumn(0L);
	if ( lCurSel < 0 || ( bUp && lCurSel < 1) || ( !bUp && lCurSel >= RowCountGet() - 1) )
		return;
	CExtGridDataProvider & dp = OnGridQueryDataProvider();
	ULONG nRowOffset = 0L; dp.CacheReservedCountsGet( NULL, &nRowOffset );
	if ( dp.SwapDroppedSeries(false, lCurSel + nRowOffset,  (bUp ? lCurSel-1 : lCurSel+2) + nRowOffset) ) {
		lCurSel = (bUp ? lCurSel-1 : lCurSel+1);
		FocusSet(CPoint(0, lCurSel));
	}
}
It’s called as a response for a button clicked. This has worked before. In the meanwhile we have changed other aspects of the application and upgraded to the newest version of Prof-UIS (v2.82). Now we get an assertion in debug mode when this method is called.

The problem is in the constructor of IDataProviderEventsMapped, because m_pOther is NULL. (ExtGridWnd.h, line 11654)
Call Stack:
- MyApp.exe!CExtMDP<CExtGridDataProviderMemory>::IDataProviderEventsMapped::IDataProviderEventsMapped(CExtMDP_MappingAPI * pMappingAPI=0x01f4ce7c, CExtGridDataProvider::IDataProviderEvents * pOther=0x00000000) Line 11654 + 0x1c
- MyApp.exe!CExtMDP<CExtGridDataProviderMemory>::SwapDroppedSeries(bool bColumns=false, unsigned long nRowColNoSrc=0x00000002, unsigned long nRowColNoDropBefore=0x00000001, CExtGridDataProvider::IDataProviderEvents * pDPE=0x00000000) Line 12333
- MyApp.exe!CMyGridWnd::MoveSelRowByOne(bool bUp=true) Line 1429 + 0x47

I’ve tried setting the last parameter of SwapDroppedSeries from the default NULL to this, but it didn’t help.

Have I messed up something or has your code changed around this area?
If the information is not enough, let me know and I’ll make a sample application.

Thank you!

Technical Support Jan 17, 2008 - 4:06 AM

There is a typing error in the CMyGridWnd::MoveSelRowByOne() method in the project you sent us. Please take a closer look at the following line:

if ( dp.SwapDroppedSeries(false, lCurSel + nRowOffset,  (bUp ? lCurSel-1 : lCurSel+2) + nRowOffset), this )
It seems to look OK, but if we step into the SwapDroppedSeries() method using the debugger, we will see NULL instead of a valid this pointer. Here is exactly the same code but we split it into several lines:
      if(   dp.SwapDroppedSeries(
                  false,
                  lCurSel + nRowOffset,
                  (bUp ? lCurSel-1 : lCurSel+2) + nRowOffset
                  ),   // ERROR
                  this // ERROR
                  )
As you can see the if operator contains the comma operator. The comma operator contains a function invocation and this value. The latter is the same as true in this case. This code is absolutely correct, but the last parameter in the invocation of the SwapDroppedSeries() method is specified by the default NULL value. Here is the correct version:
      if(   dp.SwapDroppedSeries(
                  false,
                  lCurSel + nRowOffset,
                  (bUp ? lCurSel-1 : lCurSel+2) + nRowOffset,
                  this // SWAPPED AND FIXED
                  )    // SWAPPED AND FIXED
            )
And here is the entire method:
void CMyGridWnd::MoveSelRowByOne(bool bUp)
{
      ASSERT_VALID(this);
      LONG lCurSel = SelectionGetFirstRowInColumn(0L);
      if ( lCurSel < 0 || ( bUp && lCurSel < 1) || ( !bUp && lCurSel >= RowCountGet() - 1) )
            return;
      CExtGridDataProvider & dp = OnGridQueryDataProvider();
      ULONG nRowOffset = 0L; dp.CacheReservedCountsGet( NULL, &nRowOffset );
      if(   dp.SwapDroppedSeries(
                  false,
                  lCurSel + nRowOffset,
                  (bUp ? lCurSel-1 : lCurSel+2) + nRowOffset,
                  this // SWAPPED AND FIXED
                  )    // SWAPPED AND FIXED
            )
      {
            //lCurSel = (bUp ? lCurSel-1 : lCurSel+1);
            //FocusSet(CPoint(0, lCurSel));
            OnSwInvalidate( true );
      }
}


Suhai Gyorgy Jan 17, 2008 - 6:04 AM

Now, this caused some expletives to myself, which I better not share with you! :-)

Thank you very much, you are great!

Technical Support Jan 15, 2008 - 4:31 AM

We believe the assertion failure does not depend on whether the grid is instantiated statically or dynamically. To reproduce the problem, could you modify the ProfUIS_Controls sample and send it to us?

Suhai Gyorgy Jan 15, 2008 - 5:08 AM

Modified ProfUIS_Controls sample sent.

Technical Support Jan 14, 2008 - 12:28 PM

Here is the current version of the CExtGridWnd::OnGridQueryDataProvider() virtual method which instantiates and returns the memory-based data provider for grid cells. This data provider is used by default.

CExtGridDataProvider & CExtGridWnd::OnGridQueryDataProvider()
{
      ASSERT_VALID( this );
      if( m_pDataProvider != NULL )
      {
            ASSERT_VALID( m_pDataProvider );
            return (*m_pDataProvider);
      }
      m_pDataProvider = new CExtMDP < CExtGridDataProviderMemory >;
      ASSERT_VALID( m_pDataProvider );
      return (*m_pDataProvider);
}
In the previous version of this method, a non decorated instance of the CExtGridDataProviderMemory class was used:
      m_pDataProvider = new CExtGridDataProviderMemory;
The new CExtMDP template decorator class provides a memory data provider and a grid control with the ability to hide/show rows and or columns. This feature is essential for other new grid filtering feature. That is why the SwapDroppedSeries method of the data provider component now requires a non NULL pointer to the event receiver interface that is implemented in the CExtGridWnd class. We used your code in the updated version of the CDemoGrid::OnCmdMsg() method in the SimpleGrids sample application. Here is the updated part of this method:
            if( nID == ID_USE_PAINT_MANAGER_COLORS )
            {
                  DWORD dwSiwGetStyleEx = SiwGetStyleEx();
                  BOOL bUsedPmColors =
                        ( (dwSiwGetStyleEx&__EGWS_EX_PM_COLORS) != 0 )
                              ? TRUE : FALSE;
                  if( nCode == CN_COMMAND )
                  {
//                      if( pHandlerInfo != NULL )
//                            return TRUE;
//                      SiwModifyStyleEx(
//                            bUsedPmColors ? 0 : __EGWS_EX_PM_COLORS,
//                            bUsedPmColors ? __EGWS_EX_PM_COLORS : 0,
//                            true
//                            );
                        bool bUp = CExtPopupMenuWnd::IsKeyPressed( VK_CONTROL ) ? true : false;
                        LONG lCurSel = SelectionGetFirstRowInColumn(0L);
                        if( lCurSel < 0 || ( bUp && lCurSel < 1) || ( !bUp && lCurSel >= RowCountGet() - 1) )
                              return TRUE;
                        CExtGridDataProvider & dp = OnGridQueryDataProvider();
                        ULONG nRowOffset = 0L; dp.CacheReservedCountsGet( NULL, &nRowOffset );
                        if ( dp.SwapDroppedSeries(false, lCurSel + nRowOffset,  (bUp ? lCurSel-1 : lCurSel+2) + nRowOffset, this ) )
                        {
//                            lCurSel = (bUp ? lCurSel-1 : lCurSel+1);
//                            FocusSet(CPoint(0, lCurSel));
                              OnSwInvalidate( true );
                        }
                        return TRUE;
                  } // if( nCode == CN_COMMAND )
                  else if( nCode == CN_UPDATE_COMMAND_UI )
                  {
                        CCmdUI * pCmdUI = (CCmdUI *)pExtra;
                        ASSERT( pCmdUI != NULL );
                        pCmdUI->Enable( TRUE );
                        pCmdUI->SetRadio( bUsedPmColors );
                  } // else if( nCode == CN_UPDATE_COMMAND_UI )
                  return TRUE;
            } // if( nID == ID_USE_PAINT_MANAGER_COLORS )
Now you can click the Use Paint Manager Colors button in the toolbar with or without the Ctrl key pressed and you will see the correctly swapped rows in the currently selected grid control. We used the Order Details grid with the full row selection model in our tests. Any other grid can also be used if you set the focus/selection to the first column for allowing the LONG lCurSel = SelectionGetFirstRowInColumn(0L); to detect selection. Please note, when the CExtGridWnd control receives events from the data provider component via virtual methods of the IDataProviderEvents interface, then the grid automatically manages focus and selection ranges. So, you don’t need to re-assign grid focus/selection.

Alternatively, you can simply instantiate the CExtGridDataProviderMemory class "AS IS" instead of its CExtMDP < CExtGridDataProviderMemory > decorated version used by default.

Suhai Gyorgy Jan 15, 2008 - 3:04 AM

I’ve put the code snippet to the SimpleGrid sample, as you wrote, and yes, it worked there. But I also put it in your ProfUIS_Controls sample, and I also made another, very small sample application, and both of these applications threw an ASSERT on the mentioned line. The problem is that the actual last parameter of SwapDroppedSeries is set to be a CExtGridWnd pointer in both cases, but in one of the cases it can be interpreted as an IDataProviderEvents interface just fine, and in the other case it cannot, causing the parameter to be NULL inside SwapDroppedSeries. The reason might be that one time the grid is created dynamically, other time it is subclassed from a custom control. I’m sending you the small sample application for testing purposes.

The alternative solution ( using the data provider without CExtMDP template ) worked just fine, of course, but we might want to use the filtering features in the future.