I have a task bar with tasks that I need to dynamically disable and enable. For now I am doing it by CMFCTasksPane::ShowTask, however that hides/shows the task as well, ideally I would like to grey out the task when it is not enabled. I noticed that same behavior happens when I assign to a task command that is not registered by using the ON_COMMAND macro, then it is greyed out. However I don't see how to control this behavior dynamically later. How can this be done? (ideally by using what is already provided, but not necessarily if there is no other way of course).
Here is a minimal example to demonstrate it. Into CMainFrame
I've added:
// CMainFrame class definition
CMFCTasksPane pane;
afx_msg void OnCommand1() {};
afx_msg void OnCommand2() {};
// constants
int TASKBAR_ID = 33333;
int TASK_ID1 = 34000;
int TASK_ID2 = 34001;
// BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx)
ON_COMMAND(TASK_ID1, &CMainFrame::OnCommand1)
ON_COMMAND(TASK_ID2, &CMainFrame::OnCommand2)
// CMainFrame::OnCreate
pane.Create("Pane", this, 500, FALSE, TASKBAR_ID);
pane.AddGroup("Group1");
pane.AddTask(0, "Task1", -1, TASK_ID1);
pane.AddTask(0, "Task2", -1, TASK_ID2);
pane.EnableGroupCollapse(FALSE);
pane.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&pane);
Then the tasks button are visible/clickable:
If I for example remove the ON_COMMAND macros, then it is not clickable (which is something I would like to enable/disable dynamically):
If I use the ShowTask
it is hidden completely (as expected, but not what I want):
pane.ShowTask(0, 0, FALSE);
I'll be thankful for any suggestions.
Edit: I think I found a way, although it is a bit of a hack. Basically to disable the button I do:
CMFCTasksPaneTask* task = pane.GetTask(0, 0);
task->m_uiCommandID = 1;
and to re-enable it I do:
CMFCTasksPaneTask* task = pane.GetTask(0, 0);
task->m_uiCommandID = TASK_ID1;
Seems to be working as expected, of course if there is more proper way to do this I will be glad.
The reason causing this is the involvement of the the UI Update Mechanism. And while the CMFCTasksPane
class appears to have no public members that can enable/disable the task items, the UI Update Mechanism would change them even if they did.
Indeed, having a ON_COMMAND
handler for UI item (menu, toolbar/rebar button etc) in one of your active class instances causes the item to be enabled, while not having one disables it. This can easily be seen in a MDI
project with the ON_COMMAND
handler implemented in the Document or View class; if you close all views (and subsequently all documents) the menu item or toolbar button will be automatically disabled.
By using an ON_UPDATE_COMMAND_UI
handler you can change the above default behaviour and specify the enable/disable condition based on other criteria, eg your currently selected data. The UI Update Mechanism is a very powerful feature of MFC, allowing to have the condition for updating your UI item at a single point in your code, rather than having to explicitly evaluate it (and update the item) at every point that could change it (eg when the user selects a command, changes the state of a control, selects a different set of data etc etc). The ON_UPDATE_COMMAND_UI
handlers run during idle-time processing, so you should not put any lengthy operations there. Just add a short beep command (eg Beep(500,30);
) to find out how often these are called.
See some more details and sample code in my older posts here and here.