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 » CExtPropertyGridCtrl assert when removing item that is edited Collapse All
Subject Author Date
Krister Goodh Mar 29, 2010 - 2:59 AM

Hello!


When i remove items from a CExtPropertyStore ther’s normally no problem.


After removing the items, using m_SomeCategoryPtr->ItemRemove(); I do m_PGC.PropertyStoreSynchronize(); to show the changes.


However if I click on a read-oply property (enables user to copy value to clipboard, from a CExtGridCellString) and then, while cursor is visible, execute the code above the call to m_PGC.PropertyStoreSynchronize() activates code that fails with the message:


ASSERT_VALID fails with illegal vtable pointer.
ASSERT_VALID fails with illegal vtable pointer.
Second Chance Assertion Failed: File C:\Program\FOSS Software Inc\Prof-UIS\Src\ExtPropertyGridWnd.cpp, Line 7194

from CExtPropertyGridWnd::PropertyItemFromTreeItem() (the call is passing CExtGridInplaceEdit::DoEndEdit()).


-


Am I removing items in the wrong way?

Krister Goodh Mar 29, 2010 - 9:59 AM

A partial workaround is to do:


  if (may_delete_or_edit) m_PGC.PropertyStoreSet(NULL);
  m_Store.DoSomeChanges();
  if (may_delete_or_edit) m_PGC.PropertyStoreSet(&m_Store);

This does not work for an edit field that is not disabled for editing. Still asserts.


It also has the efect that if I drop down a combo box, and while it:s dropped down delete 2 items moving a checklist into the position previously occupied by the combo, the checklist will be repopulated with the entries from the combo box!!!


 


 

Technical Support Mar 29, 2010 - 12:23 PM

Thank you for reporting us this issue. To fix it, please update the source code for the following method:

void CExtPropertyGridCtrl::PropertyStoreSynchronize()
{
            __EXT_DEBUG_GRID_ASSERT_VALID( this );
            _EnsureInitialized();
CExtPropertyGridWnd * pActivePGW = GetActiveGrid();
            if( pActivePGW->GetSafeHwnd() != NULL )
            {
                        HWND hWndInpalaceEditor = pActivePGW->GetSafeInplaceActiveHwnd();
                        if( hWndInplaceEditor != NULL )
                        {
                                    ::SendMessage( hWndInplaceEditor, WM_CANCELMODE, 0L, 0L );
                                    pActivePGW->SendMessage( WM_CANCELMODE );
                        }
            }
CExtPropertyStore * pCurrentPS = PropertyStoreGet();
CExtPropertyItem * pRestoreFocusPI = NULL;
            if( pCurrentPS != NULL )
            {
                        __EXT_DEBUG_GRID_ASSERT_VALID( pCurrentPS );
                        if( pActivePGW->GetSafeHwnd() != NULL )
                        {
                                    __EXT_DEBUG_GRID_ASSERT_VALID( pActivePGW );
                                    HTREEITEM htiFocus = pActivePGW->ItemFocusGet();
                                    if( htiFocus != NULL )
                                    //          pRestoreFocusPI = pActivePGW->PropertyItemFromTreeItem( htiFocus );
                                                pRestoreFocusPI = pActivePGW->_PropertyItemFromTreeItem_Impl( htiFocus );
                        }
            }
CTypedPtrArray < CPtrArray, CExtPropertyGridWnd * > arrGrids;
            OnPgcQueryGrids( arrGrids );
INT nGridIdx = 0;
            for( ; nGridIdx < arrGrids.GetSize(); nGridIdx ++ )
            {
                        CExtPropertyGridWnd * pGrid = arrGrids[ nGridIdx ];
                        __EXT_DEBUG_GRID_ASSERT_VALID( pGrid );
                        pGrid->PropertyStoreSynchronizeAll();
            } // for( ; nGridIdx < arrGrids.GetSize(); nGridIdx ++ )
            if( pRestoreFocusPI != NULL )
            {
                        __EXT_DEBUG_GRID_ASSERT_VALID( pActivePGW );
                        __EXT_DEBUG_GRID_ASSERT( pActivePGW->GetSafeHwnd() != NULL );
            //          HTREEITEM htiSetFocus = pActivePGW->PropertyItemToTreeItem( pRestoreFocusPI );
                        HTREEITEM htiSetFocus = pActivePGW->_PropertyItemToTreeItem_Impl( pRestoreFocusPI );
                        if( htiSetFocus != NULL )
                                    pActivePGW->ItemFocusSet( htiSetFocus );
            }
}

Krister Goodh Mar 30, 2010 - 3:11 AM

Great, this solved the first issue described, which was the most serious.


It however does not solve the issue with destroyed value lists.


How to reproduce:



  1. Have property tree with two categories, the upper category has two entries, the lower has five entries, the first is a combo box and the 4:th is a drop down check list

  2. Populate combo with some strings and check list with some strings, make all visible in a CExtPPVW < CExtPropertyGridCtrlMeterInfo >.

  3. Drop down the combo box and move the mouse over a value

  4. While the combo is open, let the program remove the upper category and it:s 2 values

  5. Click on a line in the combo

  6. Now the values from the combo box will repopulate the drop down check list 3 lines below ??!?

Technical Support Mar 30, 2010 - 5:54 AM

Here is the next improved version of the CExtPropertyGridCtrl::PropertyStoreSynchronize() method which closes any popup windows opened by any property grid cells before updating the property grid control:

void CExtPropertyGridCtrl::PropertyStoreSynchronize()
{
            __EXT_DEBUG_GRID_ASSERT_VALID( this );
            _EnsureInitialized();
CExtPropertyGridWnd * pActivePGW = GetActiveGrid();
            if( pActivePGW->GetSafeHwnd() != NULL )
            {
                        HWND hWndInplaceEditor = pActivePGW->GetSafeInplaceActiveHwnd();
                        if( hWndInplaceEditor != NULL )
                        {
                                    ::SendMessage( hWndInplaceEditor, WM_CANCELMODE, 0L, 0L );
                                    pActivePGW->SendMessage( WM_CANCELMODE );
                        }
            }
            if( CExtGridCell::g_pCellMenuTracking != NULL )
            {
                        CExtGridDataProvider * pDP = CExtGridCell::g_pCellMenuTracking->DataProviderGet();
                        if( pDP != NULL && pDP->IsKindOf( RUNTIME_CLASS(CExtTreeGridDataProvider) ) )
                        {
                                    CExtPropertyGridWnd * pActiveGrid = GetActiveGrid();
                                    if( pActiveGrid != NULL )
                                    {
                                                CExtGridDataProvider & _ActiveDP = pActiveGrid->OnGridQueryDataProvider();
                                                if( LPVOID(&_ActiveDP) == LPVOID(pDP) )
                                                            CExtPopupMenuWnd::CancelMenuTracking();
                                    }
                        }
            }
CExtPropertyStore * pCurrentPS = PropertyStoreGet();
CExtPropertyItem * pRestoreFocusPI = NULL;
            if( pCurrentPS != NULL )
            {
                        __EXT_DEBUG_GRID_ASSERT_VALID( pCurrentPS );
                        if( pActivePGW->GetSafeHwnd() != NULL )
                        {
                                    __EXT_DEBUG_GRID_ASSERT_VALID( pActivePGW );
                                    HTREEITEM htiFocus = pActivePGW->ItemFocusGet();
                                    if( htiFocus != NULL )
                                    //          pRestoreFocusPI = pActivePGW->PropertyItemFromTreeItem( htiFocus );
                                                pRestoreFocusPI = pActivePGW->_PropertyItemFromTreeItem_Impl( htiFocus );
                        }
            }
CTypedPtrArray < CPtrArray, CExtPropertyGridWnd * > arrGrids;
            OnPgcQueryGrids( arrGrids );
INT nGridIdx = 0;
            for( ; nGridIdx < arrGrids.GetSize(); nGridIdx ++ )
            {
                        CExtPropertyGridWnd * pGrid = arrGrids[ nGridIdx ];
                        __EXT_DEBUG_GRID_ASSERT_VALID( pGrid );
                        pGrid->PropertyStoreSynchronizeAll();
            } // for( ; nGridIdx < arrGrids.GetSize(); nGridIdx ++ )
            if( pRestoreFocusPI != NULL )
            {
                        __EXT_DEBUG_GRID_ASSERT_VALID( pActivePGW );
                        __EXT_DEBUG_GRID_ASSERT( pActivePGW->GetSafeHwnd() != NULL );
            //          HTREEITEM htiSetFocus = pActivePGW->PropertyItemToTreeItem( pRestoreFocusPI );
                        HTREEITEM htiSetFocus = pActivePGW->_PropertyItemToTreeItem_Impl( pRestoreFocusPI );
                        if( htiSetFocus != NULL )
                                    pActivePGW->ItemFocusSet( htiSetFocus );
            }
}

Please also make the CExtGridCell::g_pCellMenuTracking static property public.

Krister Goodh Mar 30, 2010 - 6:25 AM

When I reach this code provided by you:


 if( CExtGridCell::g_pCellMenuTracking != NULL )
 {
  CExtGridDataProvider * pDP = CExtGridCell::g_pCellMenuTracking->DataProviderGet();
  if( pDP != NULL && pDP->IsKindOf( RUNTIME_CLASS(CExtTreeGridDataProvider) ) )

the variable pDP points to a CExtGridDataProviderMemory and the last if clause in my snip above is not taken


-> problem can still be reproduced.

Technical Support Mar 31, 2010 - 6:41 AM

Yes, you are right. The pDP->IsKindOf( RUNTIME_CLASS(CExtTreeGridDataProvider) ) condition is not needed.

Krister Goodh Apr 12, 2010 - 1:00 AM

// Ups’ didn’t see your answer since it was above my question...


Well it’s not the runtime class test that is false, but rather _ActiveDP == pDP. That’s why I experimentally replaced the test by the test  _ActiveDP = pDP->m_pOuterDataProvider.


Could you please verify that this is correct? (See the code posted (i think) below at "Mar 30, 2010 - 6:54 AM".)

Krister Goodh Apr 28, 2010 - 7:13 AM

Have you had time to look at this?


The code in profuis289(2010-04-22) seems to be the same (-> i guess not working according to description above).


/J

Krister Goodh Mar 30, 2010 - 6:54 AM

Would this work???? (In CExtPropertyGridCtrl::PropertyStoreSynchronize(), slight patch on the code provided by you.)


 if( CExtGridCell::g_pCellMenuTracking != NULL )  {   CExtGridDataProvider * pDP = CExtGridCell::g_pCellMenuTracking->DataProviderGet();   if( pDP != NULL   && pDP->IsKindOf( RUNTIME_CLASS(CExtGridDataProviderMemory) )   && pDP->m_pOuterDataProvider != NULL )     {    CExtPropertyGridWnd * pActiveGrid = GetActiveGrid();    if( pActiveGrid != NULL )    { CExtGridDataProvider& _ActiveDP = pActiveGrid->OnGridQueryDataProvider();

  CExtTreeGridDataProvider * pTreeDP =    DYNAMIC_DOWNCAST( CExtTreeGridDataProvider, pDP->m_pOuterDataProvider );

if( LPVOID(&_ActiveDP) == LPVOID(pTreeDP) )  CExtPopupMenuWnd::CancelMenuTracking();    }   }  }


 

Krister Goodh Mar 30, 2010 - 3:30 AM

I have a screen shot of the event, and will send this by mail.

Krister Goodh Mar 29, 2010 - 3:15 AM

How to reproduce (using "Win32 Static MBCS Debug", ProfUIS289smd.lib in project "Property Grid Sample":



  1. In BOOL CMainDlg::OnInitDialog() , add to the end the line SetTimer(134,3000,NULL);

  2. Add function 
    void CMainDlg::OnTimer(UINT nIDEvent) 
    {
     CExtResizableDialog ::OnTimer(nIDEvent);
      if (nIDEvent == 134)
      {
        m_Btn1.SelectedStateSet( false );
        CheckMarkOnButtonChanged();
      }
    }


  3. Start aplication and quickly click on a property value so that the edit cursor is visible (ex: "RadiusInner")

  4. Wait for the timer to expire, this will reproduce my problem.