MVVM Madness:命令

JP *_*son 62 .net c# wpf design-patterns mvvm

我喜欢MVVM.我不喜欢它,但喜欢它.大部分都是有道理的.但是,我一直在阅读鼓励你编写大量代码的文章,这样你就可以编写XAML而不必在代码隐藏中编写任何代码.

让我给你举个例子.

最近我想将我的ViewModel中的命令连接到ListView MouseDoubleClickEvent.我不太清楚该怎么做.幸运的是,谷歌拥有一切的答案.我找到了以下文章:

虽然这些解决方案有助于我理解命令,但也存在问题.上述一些解决方案使WPF设计器无法使用,因为在依赖属性之后附加"内部"的常见黑客攻击; WPF设计师找不到它,但CLR可以.一些解决方案不允许多个命令到同一控件.一些解决方案不允许参数.

经过几个小时的实验,我决定这样做:

private void ListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
    ListView lv = sender as ListView;
    MyViewModel vm = this.DataContext as MyViewModel;

    vm.DoSomethingCommand.Execute(lv.SelectedItem);
}
Run Code Online (Sandbox Code Playgroud)

所以,MVVM纯粹主义者,请告诉我这有什么问题?我仍然可以单独测试我的命令.这看起来非常实用,但似乎违反了"ZOMG ...你的代码隐藏代码!!!!"的指导原则 请分享你的想法.

提前致谢.

Gre*_*g D 37

我认为错误在于纯度要求.设计模式,包括MVVM,是工具箱中的工具,而不是自己的终结.如果为了一个考虑周全的案例打破模型的纯度更有意义(并且看起来你已经考虑过这种情况),那么打破模型吧.

如果这对您有用,并且您认为这不是一个过度的维护负担,那么我会说您所做的事情没有任何问题.我认为你已经明显地承担了举证责任,尽管纯粹的MVVM实现可能是一个合理的解决方案.

(我认为这个论点类似于多范式语言的论点.虽然可以应用纯OO方法,但有时以更实用的方式处理更合适.虽然可以应用纯函数方法,但有时权衡取舍显示OO技术是值得的.)

  • 无论是MVVM还是任何其他模式,同意的过高纯度都会适得其反.我见过有人说你甚至不应该使用值转换器,因为你的视图模型应该完成所有的工作 - 紧密耦合和架构失败的确定方法.MVVM是一个(非常)有用的指导原则*如何在WPF中思考*以便使代码简单和分离.它应该永远不会成为一个坚持你的代码到一个不自然的混乱扭曲的复杂性. (9认同)

Hei*_*nzi 13

我同意你的看法,许多MVVM-Command解决方案太复杂了.就个人而言,我使用混合方法并使用ViewModel中的方法和属性在View中而不是在ViewModel中定义我的命令.

XAML:

<Window.Resources>
    <RoutedCommand x:Key="LookupAddressCommand" />
</Window.Resources>
<Window.CommandBindings>
    <CommandBinding Command="{StaticResource LookupAddressCommand}" x:Name="cmdLookupAddress" />
</Window.CommandBindings>
Run Code Online (Sandbox Code Playgroud)

代码(查看):

Private Sub cmdLookupAddress_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs) Handles cmdLookupAddress.CanExecute
    e.CanExecute = myViewModel.SomeProperty OrElse (myViewModel.SomeOtherProperty = 2)
End Sub

Private Sub cmdLookupAddress_Executed(ByVal sender As System.Object, ByVal e As System.Windows.Input.ExecutedRoutedEventArgs) Handles cmdLookupAddress.Executed
    myViewModel.LookupAddress()
End Sub
Run Code Online (Sandbox Code Playgroud)

它不是纯MVVM,但它很简单,它可以工作,它不需要特殊的MVVM命令类,它使你的代码更容易阅读非MVVM专家(=我的同事).


Tho*_*que 10

虽然我不喜欢在使用MVVM模式时编写代码隐藏,但我认为只要该代码与UI完全相关就可以.

但这不是这种情况:你从代码隐藏中调用一个view-model命令,所以它不是纯粹与UI相关的,而且在XAML中,视图和view-model命令之间的关系并不直接.

我认为您可以使用附加的命令行为轻松地在XAML中执行此操作.这样您就可以将MouseDoubleClick事件"绑定" 到视图模型的命令:

<ListView ItemSource="{Binding Items}">
   <local:CommandBehaviorCollection.Behaviors>
      <local:BehaviorBinding Event="MouseDoubleClick" Action="{Binding DoSomething}" />
   </local:CommandBehaviorCollection.Behaviors>

    ...
</ListView>
Run Code Online (Sandbox Code Playgroud)

您还可以ListView使用以下ICollectionView界面轻松访问所选项目而无需直接引用它:

private ICommand _doSomething;

public ICommand DoSomething
{
    get
    {
        if (_doSomething == null)
        {
            _doSomething = new DelegateCommand(
                () =>
                {
                    ICollectionView view = CollectionViewSource.GetDefaultView(Items);
                    object selected = view.CurrentItem;
                    DoSomethingWithItem(selected);
                });
        }
        return _doSomething;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 当我开始假装设计师不存在时,我的WPF生产力提高了. (15认同)
  • <在此处默认插入关于WPF设计器不可用的强制性笑话.> (5认同)
  • 使用新的混合行为,这种事物的附加行为不再需要打破设计师. (3认同)

Ree*_*sey 5

我相信"中的代码隐藏无代码"为目标正是,一个目标去努力的 - 不是你应该采取一个绝对的教条.有在查看代码合适的地方 - 这并不一定是哪里或如何代码可能会比另一种方法更简单的一个坏榜样.

您列出的其他方法(包括附加属性或附加事件)的优点是它们可以重复使用.当您直接挂接事件,然后执行您所做的操作时,很容易在整个应用程序中复制该代码.通过创建单个附加属性或事件来处理该连接,您可以在管道中添加一些额外的代码 - 但它的代码可以重用于任何需要双击处理的ListView.

话虽这么说,我倾向于使用更"纯粹"的方法.将所有事件处理保留在View之外可能不会影响测试场景(您专门解决),但它确实会影响整体可设计性和可维护性.通过在代码中引入代码,您将View限制为始终使用带有事件处理程序的ListView - 这会将View绑定到代码中,并限制设计人员重新设计的灵活性.