如何以编程方式 disable/enable CMFCTasksPane 中的任务而不完全隐藏它们?

How to programmatically disable/enable tasks in CMFCTasksPane without completely hiding them?

我有一个任务栏,其中包含我需要动态禁用和启用的任务。现在我正在通过 CMFCTasksPane::ShowTask 来完成它,但是 hides/shows 任务也是如此,理想情况下我想在未启用任务时将其灰显。我注意到当我分配给未使用 ON_COMMAND 宏注册的任务命令时会发生相同的行为,然后它会变灰。但是我以后看不到如何动态控制这种行为。如何才能做到这一点? (最好使用已经提供的,但如果没有其他方法当然不一定)。

这是一个演示它的最小示例。在 CMainFrame 中我添加了:

// 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);

那么任务按钮是visible/clickable:

例如,如果我删除了 ON_COMMAND 宏,那么它就不可点击(这是我想要动态 enable/disable 的东西):

如果我使用 ShowTask 它会完全隐藏(如预期的那样,但不是我想要的):

pane.ShowTask(0, 0, FALSE);

如有任何建议,我将不胜感激。

编辑: 我想我找到了一种方法,尽管它有点乱七八糟。基本上禁用我做的按钮:

CMFCTasksPaneTask* task = pane.GetTask(0, 0);
task->m_uiCommandID = 1;

要重新启用它,我会这样做:

CMFCTasksPaneTask* task = pane.GetTask(0, 0);
task->m_uiCommandID = TASK_ID1;

似乎按预期工作,当然,如果有更合适的方法来做到这一点,我会很高兴。

造成这种情况的原因是UI Update Mechanism的参与。虽然 CMFCTasksPane class 似乎没有 public 成员可以 enable/disable 任务项目,但 UI 更新机制会改变他们,即使他们有。

确实,在您的一个活动 class 实例中为 UI 项目(菜单、toolbar/rebar 按钮等)设置 ON_COMMAND 处理程序会导致启用该项目,虽然没有禁用它。这可以很容易地在 MDI 项目中看到,其中 ON_COMMAND 处理程序在文档或视图 class 中实现;如果您关闭所有视图(随后关闭所有文档),菜单项或工具栏按钮将自动禁用。

通过使用 ON_UPDATE_COMMAND_UI 处理程序,您可以更改上述默认行为并根据其他条件(例如您当前选择的数据)指定 enable/disable 条件。 UI 更新机制是 MFC 的一个非常强大的功能,它允许在代码中的单个点上有更新 UI 项目的条件,而不必显式评估它(并更新项目) 在每个可能改变它的点上(例如,当用户选择一个命令、改变控件的状态、选择一组不同的数据等时)。 ON_UPDATE_COMMAND_UI 处理程序 运行 在 idle-time 处理期间,所以你不应该在那里放置任何冗长的操作。只需添加一个短促的蜂鸣声命令(例如 Beep(500,30);)即可了解它们被调用的频率。

在我的旧帖子中查看更多详细信息和示例代码 here and