4

我正在为我的 WPF 数据输入屏幕编写撤消日志,它将跟踪所有控件的更改。当用户选择撤消时,我不仅要恢复最新的更改,还要将焦点放回其值正在恢复的控件中。我正在努力寻找将注意力重新集中的最佳方式。

我的 ViewModel 将是处理撤销日志的部分:ViewModel 的属性设置器将在更新 DataModel 之前捕获一些“之前”状态。一种或另一种方式,“之前”状态需要包含足够的信息,以便我能够稍后将焦点放回原处。

举例来说,假设有两个数据输入字段:地址和城市。ViewModel 对每个都有一个属性,View 对每个绑定到相应 ViewModel 属性的 TextBox 都有一个。

让我们按照用户刚刚在地址字段中键入一个值,然后单击城市字段的示例进行操作。我正在使用默认的 UpdateSourceTrigger.LostFocus 行为,因此当地址文本框失去焦点时,地址更改会被保存。到目前为止,关于如何解决这个问题,我有三种不同的想法,但我对 WPF 的了解不够多,无法知道如何使它们中的任何一个起作用。

  1. 我可以忘记 MVVM 样式的数据绑定,并挂钩编辑控件的 LostFocus 事件(或添加附加行为,或制作包装 TextBox 的自定义控件,或者......)。在 LostFocus 事件处理程序中,我可以创建一个撤消帧,其中包含对事件发送者的引用。后来,在撤消之后,我只关注我保存了其引用的控件。这可能是我在 WinForms 中所做的,但在 WPF 中我宁愿坚持使用 ViewModel 模式——我宁愿让日志逻辑存在于 ViewModel 中而不是 View 中,以确保可测试性。所以这个选项不是我的第一选择。

  2. 在我的 ViewModel 的属性设置器中,我可以捕获正在设置的 ViewModel 属性的名称(本示例中的“地址”),并将该名称存储在撤消框架中。稍后,在撤消时,我可以遍历视图中的所有控件,寻找我能找到的第一个绑定到名为 Address 的属性的控件。一旦我找到一个这样的控制,我就会把重点放在它上面。这足以满足我的需要,因为我不希望将多个控件绑定到同一个 ViewModel 属性。问题是这需要深入研究绑定表达式,这是我不知道该怎么做的事情。(它还会引入更多基于名称的后期绑定,如果我重构,可能会中断。)

  3. 当我的 ViewModel 将更改添加到撤消堆栈时,它可以要求 View 层(通过接口)创建一个知道哪个控件具有焦点的 Memento。在撤消时,日记会要求视图恢复该备忘录。这里的问题是,当我的 ViewModel 的属性被设置并添加撤消框架时,键盘焦点已经移动到 City TextBox,因此“创建纪念品”需要比“哪里”更棘手当前的键盘焦点”,我不知道如何完成这个技巧。

任何人对进行上述任何工作有任何建议,或者有可能更好的替代方法?

4

1 回答 1

1

我将从您的第二种方法开始。但是,我不会深入研究绑定列表,而是将控件的高亮属性硬编码为 VM 属性。

例如,这是我的虚拟机:

public class VM
{
    public double Price { get; set; }
    public bool PriceHighlighted { get; set; }
}

然后,将 Price 属性绑定到 TextBox 并将 TextBox 的背景绑定到 PriceHighlighted(使用值转换器)。现在 VM 可以完全控制视图的反应方式。当用户执行“撤消”操作时,VM 可以将所有 xxxHightlighted 设置为 false,除了您要突出显示的那个。

于 2009-05-17T15:21:52.733 回答