65.9K
CodeProject 正在变化。 阅读更多。
Home

数据驱动的 UI 行为模型

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.24/5 (14投票s)

2003年10月17日

4分钟阅读

viewsIcon

62315

downloadIcon

569

如何在 MFC 中建模一个数据驱动的 UI 行为模型来满足“所有内容都在一个屏幕上”的需求

引言

Sample screenshot

最近,我遇到了一个非常庞大(fat)的 C++ 客户端应用程序。它包含了非常丰富的 GUI 元素,用于设置和发送协议消息。但它存在一个严重的设计问题,所有的 UI 行为逻辑都写在了 Windows 消息处理函数中,有时甚至连数据模型也深埋其中,难以查看。

假设你有一个包含大约 30 个控件的对话框,其中 20 个控件的每一次移动都会改变其他控件的行为(启用/隐藏/设置默认值/改变约束等)。如果你没有正确地建模这种复杂性,很快就会陷入逻辑地狱,因为会出现看不见的递归函数调用或逻辑矛盾。而这正是我目前面临的现实。

但要正确地建模它,必须遵循太多规则

  1. 切勿将数据与逻辑混合。
  2. 切勿在消息处理函数中调用另一个消息处理函数。
  3. 保持现有逻辑图的良好跟踪,但图在哪里!?

有些朋友可能会说,你不应该在一个窗口中放置如此多的控件。我不得不同意这一点,但我相信我们都遇到过难缠的客户或真正的难缠的产品经理,他们肯定喜欢“把一切都放在一个屏幕上”。

“把一切都放在一个屏幕上!”听起来很疯狂!但这种情况在很多需求中确实会发生,尤其是在管理应用程序、操作员控制台等场景下。

所以,当实在没有办法绕开时,我们就必须以某种方式进行建模。

方法

在我开始构建我的解决方案之前,有几个思路

  1. 控件的状态受数据模型影响,而不是像看起来那样受其他控件影响。它们的变化仅仅是因为当前正在处理的数据发生了变化。这种变化可能由对话框上的组合框选择引起,但该组合框不应该触发你的控件变化,而是 DATA(数据)。这是数据驱动的关键。
  2. ON_UPDATE_COMMAND_UI 是一个我们可以依赖的很好的消息模型。但不应该使用 WM_KICKIDLE,它会浪费 CPU 并导致 GUI 中出现意外行为。UpdateDialogControls() 是广播 GUI 中变化的非常好的方法。
  3. 一些 Context 类在定义数据模型快照状态时会非常有用。此外,可以在 Context 类中添加复杂的检查,以支持额外的计算、逻辑建模等。Context 类应该继承自 Data Model 类,因为它们的结构相同。
  4. 然后,Context 类实例可以被具有相同数据模型依赖性的控件重用。例如,当电力中断时,你不能打开灯,也不能看电视。听起来很有趣?:-)

为什么要使用数据驱动模型?!

我相信这是对我们自然世界的模拟。再次以灯光为例。假设你有一个复选框代表电灯开关。取消选中表示关闭,选中表示打开,这将改变你房间(对话框)中其他事物的可见性。你可能会注意到,是黑暗或光明影响了可见性,而不是开关的动作。开关可能发生故障,无论你如何操作,灯仍然是灭的,而且因为黑暗你仍然看不到任何东西!

好的,回到代码对应部分。如果你根据开关的选中事件编写了用户行为,那么所有 UI 逻辑将保持不变,无论开关本身如何,甚至包括对话框之前的状态(当时是明亮还是黑暗?)。除非你喜欢为每个其他控件重复检查所有条件是否满足,而你可以简单地检查一个数据成员(现在还暗吗?)!这有意义吗?

这很简单,但却是我们都犯过或正在犯的一个常见错误。我也同意,对于思维简单的人来说,这是完全不必要的。但如果你被要求在一个屏幕上包含 20 个控件,我认为这会有帮助。

演示中有什么?

基于以上考虑,我编写了演示应用程序。看完代码后,你肯定会明白我的意思。如果你在理解 MFC 方面遇到困难,那么你可能需要阅读一些 MSDN,但我相信对大多数开发者来说,这相当直接。

Cooperate Diagram

为了简洁起见,我包含了一个只有一个成员变量的数据对象。它与其他对话框成员一起用于确定“后续控件”的状态。在实际生活中,你可能会有完全独立于表示代码的业务逻辑对象。对我来说,除了数据模型实例之外,这些对话框成员都与表示相关。

顺便说一下

我在本项目中使用了我的 CCheckedGroupBox 来演示处理自定义控件的一些情况。如果你喜欢,请随时参考我之前关于它的文档。

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.