【问题标题】:WPF Mutate Command PatternWPF 变异命令模式
【发布时间】:2013-11-13 15:43:31
【问题描述】:

我应该改变传递给 ICommand 上 Execute 方法的参数吗?如果不是,在调用命令后更改应用程序或视图模型的状态的最佳方法是什么?

想法

命令模式调用对象的方法,在 WPF 的情况下,它是模型或视图模型。这需要模型知道如何对自己执行操作。我们都看过并使用过 RelayCommand 实现。我遇到的问题是很难换掉行为。也很难找到放置“特殊情况”代码的地方。如果我想显示另一个视图怎么办?

我喜欢为每个用例创建一个命令的想法。我将有一个实现 ICommand 的具体类,该类处理执行用例的逻辑。这需要对模型的引用,就像命令模式一样。不同之处在于动作逻辑将在模型之外,因此会改变作为参数传入的模型。让我们看一些示例代码。

我有一个显示无处不在的 Person 对象列表的窗口。我们想在 Person 上调用一个命令来清除他们的名字。 MainViewModel 有一个名为 People 的 Person 对象集合。

 <Window.Resources>
    <commands:ClearNameCommand x:Key="ClearNameCommand"/>
</Window.Resources>
<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>

这是我绑定到集合的列表框,并显示每个人都有一个按钮来清除他们的名字。

<ListBox ItemsSource="{Binding People}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Name" Width="100"/>
                    <TextBox Text="{Binding Name}" Width="100"/>
                    <Button Command="{StaticResource ClearNameCommand}" CommandParameter="{Binding}" Content="Clear"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

下面是具体类 ClearNameCommand 的 Execute 方法。它会显示一个对话框,询问他们是否要执行该操作。我认为这是一个很好的例子,说明了为什么您不会将此命令放入模型中。还想象一下,您必须在某个名称被清除的地方登录?撤消重做也许?所有这些代码都去哪儿了??!!

public void Execute(object parameter)
    {
        Person p = parameter as Person;
        if (p != null)
        {
            if (MessageBox.Show(
                "Are you sure you want to clear the name?", 
                "Clear Name", 
                MessageBoxButton.YesNo, 
                MessageBoxImage.Question) == MessageBoxResult.Yes)
            {
                p.Name = "";
            }
        }
    }

我想您可以将所有准备代码留在命令中,然后在 Person 上调用 Clear 方法。但是,我仍然不相信这是最好的方法。如果明确改变怎么办?你最终得到 Clear2 和 Clear3 等等。更不用说每个可能的用例甚至更多的方法。

更多想法

假设我有一个视图模型,它引用了一个允许传递数据绑定的模型,或者它将模型全部包装在一起。我想要摆脱的是在视图模型上为每个用例创建一个命令属性。另外,那个设计有什么好干净的?您仍在 Execute 方法中更改 Model 对象。我认为我并没有过多地弯曲命令模式。我的窗口是客户端。模型是接收者。按钮是调用者。唯一的区别是您使用调用程序注入依赖项。

稍微改一下我的问题,有没有人看到这样做的任何危险信号?

我在研究命令模式时发现了这一点。 http://msdn.microsoft.com/en-us/library/cc984279.aspx

【问题讨论】:

    标签: wpf command-pattern


    【解决方案1】:

    我真的不知道你在说什么......你似乎有一种非常......呃,独特的与Commands合作的方式。

    这要求模型知道如何对自己执行操作。

    模型类中不应该有Commands...相反,将它们放在显示该模型类的任何视图模型中。

    ...很难换掉行为

    再一次……什么?不要“交换行为”。 Command 不应更改其功能。只需为每个函数创建一个。

    也很难找到放置“特殊情况”代码的地方

    什么是“特殊情况”代码?

    如果我想显示另一个视图怎么办?

    每个视图都应该有自己的视图模型。每个视图模型都应该有自己的一组ICommand 对象。如果您必须在RelayCommand 中复制一个小的Lambda 表达式,这真的不是问题。

    想象您必须在某个名称被清除的地方登录?撤消重做可能?所有这些代码都去哪儿了??!!

    视图模型,视图模型,视图模型。

    我想您可以将所有准备代码留在命令中,然后在 Person 上调用 Clear 方法

    您认为调用p.Name = "" 和调用p.ClearName() 之间的区别是什么?没有区别,或者最多,调用方法比直接设置属性花费的时间稍长。

    如果明确发生变化怎么办?你最终得到 Clear2 和 Clear3 等等

    再一次……什么??? Name = "" 会如何变化?

    虽然我希望我回答了一些您的问题,但我认为我一定在某种程度上误解了您,因为我不完全理解您的问题。请随时提出进一步的问题,但请将它们添加为您的问题的编辑,我将在此答案中回复,以免 cmets 变得荒谬。


    更新>>>

    响应前两个cmets:

    是的...在几乎所有情况下,我都会为一个视图模型提供一个视图。不,从Command 更改anything 的值绝对没有问题。我想不出有什么理由让你认为那不行。想象一下这个场景:

    UI 中有一个对象列表和一个编辑面板,用户可以使用它来编辑对象。您还有一个 Button 和一个名为 DuplicateCommand。现在,根据定义,Command 将像您所说的那样“变异”,即数据对象或模型类。

    它将创建一个新对象并根据当前选定对象的值设置其属性。您是否建议这个Command 这样做是错误的?在我看来,绝大多数Command(或方法)功能都会“改变”视图中数据对象的一些属性或属性……我们还能如何提供这种有用的功能?

    然后继续“这应该在哪里?”问题......它还能在哪里?在视图模型中,我们可以访问当前选定的项目整个项目集合。从视图模型中,我们可以访问为我们提供各种功能的任意数量的服务。您会发现很难从单独的 Command 类中与其中一些内容联系起来。

    【讨论】:

    • 感谢您的回复。我想我必须稍微澄清一下这个问题。是为每个模型创建视图模型的人之一吗?
    • 所以澄清一下,您没有发现在命令中改变模型有什么问题,无论命令是 ViewModel 上的 RelayCommand 还是具体类??
    • 谢谢谢里登。我在左外野没有出路。我认为这是一个合理的问题。通常不赞成更改作为参数传递的对象。在任何 GoF 模式中都找不到它。甚至不是命令模式。 WPF 中的 Command 属性并没有真正遵循命令模式。我绝对看到在视图模型上使用命令的价值。我一直在使用它们。我只是认为有时我们会创建一个具体的命令类。也许在运行时添加功能。
    猜你喜欢
    • 1970-01-01
    • 2010-09-14
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    • 2017-12-06
    • 2015-10-18
    • 1970-01-01
    • 2016-05-03
    相关资源
    最近更新 更多