Nie można zmienić stan elementu menu z jego obsługi interfejsu użytkownika polecenie, jeśli menu jest dołączony do okna dialogowego w programie Visual C++


Obsługa programu Microsoft Visual C++ .NET 2002 i Microsoft Visual C++ .NET 2003 Uwaga model kodu zarządzanego przez Microsoft.NET Framework i modelu kodu niezarządzanego macierzystego Microsoft Windows. Informacje zawarte w tym artykule dotyczą tylko niezarządzanego kodu Visual C++. Microsoft Visual C++ 2005 obsługuje model kodu zarządzanego, dostarczonego przez Microsoft.NET Framework i model niezarządzanego kodu Microsoft Windows macierzystego.

Symptomy


Zmiana stanu elementu menu (Włączanie/wyłączanie, zaznacz/Odznacz, zmień tekst) z jego polecenia obsługi interfejsu użytkownika (UI) nie działa poprawnie, jeśli menu jest dołączony do okna dialogowego:
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.}

Przyczyna


Po wyświetleniu menu rozwijanego WM_INITMENUPOPUP wiadomości jest przed wyświetleniem elementów menu. Funkcja MFC CFrameWnd::OnInitMenuPopup iterację elementów menu i wywołuje obsługi interfejsu użytkownika polecenie aktualizacji dla towaru, jeśli istnieje. Wygląd każdego elementu menu jest aktualizowany w celu odzwierciedlenia stanu (włączony/wyłączony, sprawdzane niezaznaczone). Aktualizacja mechanizmu interfejsu użytkownika nie działa dla aplikacji opartych na polu dialogowym, ponieważ CDialog ma obsługi OnInitMenuPopup i wykorzystuje CWnddomyślnym programem obsługi, która nie wymaga obsługi interfejsu użytkownika polecenie aktualizacji dla elementów menu.

Rozwiązanie


Aby rozwiązać ten problem, wykonaj następujące kroki:
  1. Dodaj wpis ON_WM_INITMENUPOPUP do mapy wiadomości:
    BEGIN_MESSAGE_MAP(CTestDlg, CDialog)//}}AFX_MSG_MAPON_WM_INITMENUPOPUP()END_MESSAGE_MAP()
  2. Dodawanie funkcji składowej OnInitMenuPopup do klasy okno dialogowe i skopiuj poniższy kod (należy zauważyć, że ten kod jest pobierana w dużej mierze z CFrameWnd::OnInitMenuPopup w WinFrm.cpp):
    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;    }}

Stan


Takie działanie jest celowe.

Więcej informacji


Mechanizm obsługi interfejsu użytkownika polecenie aktualizacji jest również nazywany z CWnd::OnCommand , aby upewnić się, że polecenie nie stały się niepełnosprawne przed routingu. Dlatego program obsługi poleceń nie jest wywoływana dla wyłączonego elementu menu, mimo że nie jest wyszarzone (niedostępne). Elementy menu nie są rysowane w tym przypadku odzwierciedlają ich stan. Jest to kod powiązanych z pliku 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;   }

Kroki prowadzące do odtworzenia problemu

Wykonaj następujące kroki, aby odtworzyć ten problem w programie Visual C++ .NET:
  1. Tworzenie aplikacji MFC okno dialogowe za pomocą AppWizard.
  2. Tworzenie nowego zasobu menu i dodać do niego elementy menu plik oraz Plik/wyjścia .
  3. Ustaw w tym menu jako menu dla okna dialogowego, w oknie dialogowym właściwości pola. Aby to zrobić, Otwórz okno dialogowe zasób edytora okien dialogowych. W oknie dialogowym właściwości kliknij opcję Wybierz Menu. Identyfikator nowego zasobu menu jest wyświetlany na liście rozwijanej Menu edytora właściwości.
  4. Dodawanie obsługi UPDATE_COMMAND_UI dla elementu menu Plik/Exit . Aby to zrobić, klikając prawym przyciskiem myszy Plik/Zakończ Edytor menu, a następnie kliknij Dodaj program obsługi zdarzeń. W Kreatorze obsługi zdarzeń dodać obsługi UPDATE_COMMAND_UI projekt CDialog pochodne klasy. Kliknij Dodawanie i edytowanie do tworzenia programu obsługi, a następnie dodać jeden z tych instrukcji do metody obsługi wygenerowany:
    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. Tworzenie i uruchamianie aplikacji.

Informacje


Aby uzyskać więcej informacji, kliknij następujący numer artykułu w celu wyświetlenia tego artykułu z bazy wiedzy Microsoft Knowledge Base:
141751 dodawanie pasków do okien dialogowych w MFC