U kunt de status van een menu-item uit de opdracht gebruikersinterface-handler niet wijzigen als het menu is gekoppeld aan een dialoogvenster in Visual C++


Opmerking Microsoft Visual C++ .NET 2002 en Microsoft Visual C++ .NET 2003 de beheerde code model wordt ondersteund door het Microsoft .NET Framework en de niet-beheerde native Microsoft Windows code model. De informatie in dit artikel geldt alleen voor Visual C++-code zonder begeleiding. Microsoft Visual C++ 2005 ondersteunt zowel het objectmodel voor beheerde code die wordt geleverd door Microsoft .NET Framework en het model zonder begeleiding native Microsoft Windows-code.

Symptomen


De status van een menu-item (inschakelen of uitschakelen, schakelt u controle /, tekst wijzigen) wijzigen van de gebruikersinterface (UI) opdrachthandler werkt niet goed als het menu is gekoppeld aan een dialoogvenster:
void CTestDlg::OnUpdateFileExit(CCmdUI* pCmdUI) {    pCmdUI->Enable(FALSE); //Not calling the command handler, but does not show as disabled.    pCmdUI->SetCheck(TRUE); // Does not show check mark before the text.    pCmdUI->SetRadio(TRUE); // Does not show dot before the text.    pCmdUI->SetText("Close"); //Does not change the text.}

Oorzaak


Als een vervolgmenu wordt weergegeven, wordt het bericht WM_INITMENUPOPUP verzonden voordat de menu-items weer te geven. De MFC- CFrameWnd::OnInitMenuPopup -functie doorloopt de menu-items en de update opdracht UI-handler wordt aangeroepen voor het artikel, als er een. Het uiterlijk van elk menu-item is bijgewerkt met de status (ingeschakeld/uitgeschakeld, ingeschakeld/uitgeschakeld). De update-mechanisme UI werkt niet voor een dialoogvenster vak gebaseerde toepassing omdat CDialog geen OnInitMenuPopup -handler en de CWndvan standaard-handler die geen update opdracht UI-handlers voor menu-items roept worden gebruikt.

Oplossing


Gebruik de volgende stappen uit om dit probleem oplossen door:
  1. Een ON_WM_INITMENUPOPUP vermelding toevoegen aan het bericht toewijzen:
    BEGIN_MESSAGE_MAP(CTestDlg, CDialog)//}}AFX_MSG_MAPON_WM_INITMENUPOPUP()END_MESSAGE_MAP()
  2. OnInitMenuPopup lidfuncties toevoegen aan uw dialoogvensterklasse en kopieer de volgende code (Let erop dat deze code grotendeels uit CFrameWnd::OnInitMenuPopup in WinFrm.cpp genomen):
    void CTestDlg::OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu){    ASSERT(pPopupMenu != NULL);    // Check the enabled state of various menu items.    CCmdUI state;    state.m_pMenu = pPopupMenu;    ASSERT(state.m_pOther == NULL);    ASSERT(state.m_pParentMenu == NULL);    // Determine if menu is popup in top-level menu and set m_pOther to    // it if so (m_pParentMenu == NULL indicates that it is secondary popup).    HMENU hParentMenu;    if (AfxGetThreadState()->m_hTrackingMenu == pPopupMenu->m_hMenu)        state.m_pParentMenu = pPopupMenu;    // Parent == child for tracking popup.    else if ((hParentMenu = ::GetMenu(m_hWnd)) != NULL)    {        CWnd* pParent = this;           // Child windows don't have menus--need to go to the top!        if (pParent != NULL &&           (hParentMenu = ::GetMenu(pParent->m_hWnd)) != NULL)        {           int nIndexMax = ::GetMenuItemCount(hParentMenu);           for (int nIndex = 0; nIndex < nIndexMax; nIndex++)           {            if (::GetSubMenu(hParentMenu, nIndex) == pPopupMenu->m_hMenu)            {                // When popup is found, m_pParentMenu is containing menu.                state.m_pParentMenu = CMenu::FromHandle(hParentMenu);                break;            }           }        }    }    state.m_nIndexMax = pPopupMenu->GetMenuItemCount();    for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;      state.m_nIndex++)    {        state.m_nID = pPopupMenu->GetMenuItemID(state.m_nIndex);        if (state.m_nID == 0)           continue; // Menu separator or invalid cmd - ignore it.        ASSERT(state.m_pOther == NULL);        ASSERT(state.m_pMenu != NULL);        if (state.m_nID == (UINT)-1)        {           // Possibly a popup menu, route to first item of that popup.           state.m_pSubMenu = pPopupMenu->GetSubMenu(state.m_nIndex);           if (state.m_pSubMenu == NULL ||            (state.m_nID = state.m_pSubMenu->GetMenuItemID(0)) == 0 ||            state.m_nID == (UINT)-1)           {            continue;       // First item of popup can't be routed to.           }           state.DoUpdate(this, TRUE);   // Popups are never auto disabled.        }        else        {           // Normal menu item.           // Auto enable/disable if frame window has m_bAutoMenuEnable           // set and command is _not_ a system command.           state.m_pSubMenu = NULL;           state.DoUpdate(this, FALSE);        }        // Adjust for menu deletions and additions.        UINT nCount = pPopupMenu->GetMenuItemCount();        if (nCount < state.m_nIndexMax)        {           state.m_nIndex -= (state.m_nIndexMax - nCount);           while (state.m_nIndex < nCount &&            pPopupMenu->GetMenuItemID(state.m_nIndex) == state.m_nID)           {            state.m_nIndex++;           }        }        state.m_nIndexMax = nCount;    }}

Status


Dit gedrag is inherent aan het ontwerp van het product.

Meer informatie


De update opdracht UI-handler is een afkorting van CWnd::OnCommand om te controleren of de opdracht niet worden uitgeschakeld voordat u routering. Dit is de reden waarom de opdrachthandler niet wordt aangeroepen voor een menuopdracht uitgeschakeld, hoewel het niet grijs (niet beschikbaar). Menu-items worden niet getekend om hun status in dit geval weer te geven. Dit is de bijbehorende code uit het bestand Wincore.cpp:
   // Make sure command has not become disabled before routing.   CTestCmdUI state;   state.m_nID = nID;   OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL);   if (!state.m_bEnabled)   {      TRACE1("Warning: not executing disabled command %d\n", nID);      return TRUE;   }

Het probleem reproduceren

Ga als volgt te werk om dit probleem in Visual C++ .NET reproduceren:
  1. Een dialoogvenster gebaseerd MFC-toepassing maken met behulp van AppWizard.
  2. Een nieuw Menubron maken en de menu-items van het bestand en het Bestand/afsluiten aan toevoegen.
  3. Dit menu instellen als het menu voor het dialoogvenster in het dialoogvenster voor de eigenschappen van vak. Open hiertoe het dialoogvenster resource in het dialoogvenster editor. Klik in het venster Eigenschappen, selecteer Menu. De ID van de Menubron van het nieuwe wordt weergegeven in het Menu eigenschap editor vervolgkeuzelijst.
  4. Een UPDATE_COMMAND_UI-handler voor Bestand/afsluiten menu-item toevoegen. Dit doet u door met de rechtermuisknop op Bestand/afsluiten in het menu-editor en klik vervolgens op Gebeurtenis-Handler toevoegen. In de wizard gebeurtenis-Handler toevoegen de handler UPDATE_COMMAND_UI aan het project CDialog afgeleide klasse. Klik op toevoegen en bewerken als de handler wilt maken en vervolgens een van de volgende instructies aan de gegenereerde handler-methode toevoegen:
    pCmdUI->Enable(FALSE); //Not calling the handler, but does not show as disabledpCmdUI->SetCheck(TRUE); // Does not show check mark before the text.pCmdUI->SetRadio(TRUE); // Does not show dot before the text.pCmdUI->SetText("Close"); //Does not change the text.
  5. Bouwen en uitvoeren van de toepassing.

Verwijzingen


Klik op het volgende artikelnummer in de Microsoft Knowledge Base voor meer informatie:
141751 toevoegen grepen voor dialoogvensters in MFC