撤消日记功能:将控件重置为撤消

时间:2009-05-12 12:33:58

标签: wpf mvvm focus undo

我正在为我的WPF数据输入屏幕编写一个撤消日志,它将跟踪所有控件的更改。当用户选择撤消时,我不仅要还原最新的更改,还要将焦点放回正在还原其值的控件中。我正在努力解决这个问题的最佳方式。

我的ViewModel将是处理撤消日记的部分:ViewModel的属性设置器将在更新DataModel之前捕获一些“之前”状态。无论如何,“之前”状态需要包含足够的信息,以便我能够稍后重点关注。

为了说明,假设有两个数据输入字段:地址和城市。 ViewModel为每个都有一个属性,View为每个绑定到相应ViewModel属性的TextBox提供了一个TextBox。

让我们按照用户刚刚在“地址”字段中键入值的示例,然后单击“城市”字段。我正在使用默认的UpdateSourceTrigger.LostFocus行为,因此当Address TextBox失去焦点时,会保存地址更改。到目前为止,关于如何处理这个问题,我有三个不同的想法,但我不知道有关WPF的详细信息,知道如何让它们工作。

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

  2. 在我的ViewModel的属性设置器中,我可以捕获正在设置的ViewModel属性的名称(在此示例中为“Address”),并将该名称存储在撤消帧中。稍后,在Undo上,我可以遍历View中的所有控件,寻找我能找到的第一个绑定到名为Address的属性的控件。一旦我找到一个这样的控件,我就把它集中注意力。这对于我需要的东西来说已经足够了,因为我不希望将多个控件绑定到同一个ViewModel属性。问题是这需要挖掘绑定表达式,这是我不知道该怎么做。 (它还会引入更多基于名称的后期绑定,如果我重构,可能会破坏。)

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

  4. 任何人对上述任何工作有任何建议,或者有其他可能更好的方法吗?

1 个答案:

答案 0 :(得分:1)

我会从你的第二种方法开始。但是,我不是通过绑定列表挖掘,而是将控件的highlight属性硬编码为VM属性。

例如,这是我的VM:

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

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