WPF使用自定义RoutedUICommands还是简单的事件处理程序?

时间:2009-02-17 19:13:23

标签: wpf xaml routed-commands

我今天正在和某人讨论如何在他们的WPF程序中选择如何处理逻辑的设计模式,并希望SO社区可以提供进一步的建议以使决策更容易。 支持命令的哪些因素超过了不便之处?

我准备了一个完整的sample以及前三种方法中的一些UML diagrams

  1. 在按钮和菜单上使用Click事件处理程序。
  2. 使用XAML中绑定的命令。
  3. 使用代码中绑定的命令,保留XAML以实现纯GUI布局和样式。
  4. 他上过的入门课程和许多书籍都展示了简单的Click事件处理程序,作为将逻辑连接到UI对象的自然方式。

    在代码隐藏文件中创建命令时使用命令所需的开销量让他感到有些震惊:

    public static readonly ICommand cmdShow2 = new RoutedUICommand(
      "Show Window2", "cmdShow2", 
      typeof(TestDespatchWindow));
    

    然后更多的代码在XAML中以罗嗦的方式命令必须被识别和绑定:

    <Window x:Class="WPFDispatchDemo.TestDespatchWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:w="clr-namespace:WPFDispatchDemo"..>
    
        <Window.CommandBindings>
          <CommandBinding Command="{x:Static w:TestDespatchWindow.cmdShow2}"
            Executed="OnShow2" />
        </Window.CommandBindings>
          <DockPanel>
            <StackPanel Margin="0,8,0,0">
              <Button x:Name="Show2EventBased" 
                      Margin="10,2,10,2" 
                      Click="OnShow2" 
                      Content="Show2 via WPF Event"/>
              <Button x:Name="Show2Command" 
                      Command="{x:Static w:TestDespatchWindow.cmdShow2}"
                      Margin="10,2,10,2" 
                      Content="Show2 via WPF"/>
            </StackPanel>
        </DockPanel>
      </Window>
    

    我不能(还)声称自己是WPF专家,所以我可能把事情描绘得比实际情况更复杂,但我怀疑你不能简化事情而不是上述事情。

    修改

    我在DelegateCommand,RoutedCommand和Event之间找到了一个有趣的3-way comparison

4 个答案:

答案 0 :(得分:6)

命令各有利弊,你必须根据自己的情况选择, 我强烈建议你在案例的基础上做出选择,不要为整个项目选择“一个真正的方式”。

对于某些情况,发送方和接收方之间的分离以及仅使用XAML发送命令的能力是一个很大的优势(例如,看看ScrollBar控制模板如何与http://msdn.microsoft.com/en-us/library/ms742173.aspx处的控制逻辑进行通信)。 / p>

在其他情况下,命令可以将2行事件处理程序变成一些不可能跟随怪物,包括更改应用程序中的4个单独位置(How should the ViewModel close the form?)。

答案 1 :(得分:3)

唯一的原因是熟悉命令注册表。意味着事件可能是私有方法,我觉得它们与窗口代码紧密结合。同时,Commands提供了分别保持实现(事件)和定义(Command)的能力,你甚至可以使用另一个类(看看ApplicationCommands)。

此外,当我正在进行WPF工作时,我使用ICommand(Command Pattern)的实现。该命令的所有逻辑都转到Execute方法。这有助于我以更加结构化的方式保持逻辑分离,而不会过度复杂的窗口代码。使用此选项,您可以在模型上创建命令,从而将它们绑定到无噪音。看一看。

创建模型。

public class Model
{
  ICommand CloseMessagePopupCommand {get; set;}
}

然后分配数据上下文

public MainWindow()
{

  this.DataContext = new Model();
}

并使用以下XAML代码。

<Button 
    Command="{Binding CloseMessagePopupCommand}"
    Content="{StaticResource Misc.Ok}" />

答案 2 :(得分:2)

我尝试坚持使用Andy的#2和#3方法组合开发WPF应用程序时Mike所指的命令模式。

我认为在我的视图中只有一个命令的缺点:只有某些UI元素的某些动作才会调用命令。解决此问题的一种方法是让事件处理程序在命令上调用Execute方法。我认为这些命令提供了一种封装执行逻辑的好方法。如果您维护大量UI并使用MVC / MVC / MVVM模式实现它,这将变得非常明显。

我建议你看一下关于DataModel-View-ViewModel模式的Dan Crevier系列,特别是关于命令和封装命令的部分。即使这种模式不能满足您的需求,它也可以很好地概述如何将逻辑封装在一个单独的类中。

答案 3 :(得分:1)

ICommand的其他变体似乎是实现复杂命令结构的一种流行方式。

Brian Noyes在他的article on PRISM中说

WPF中的路由命令非常强大且有用,但在应用于复合应用程序时存在一些缺点。第一个是它们完全耦合到可视树 - 调用者必须是可视树的一部分,并且命令绑定必须通过可视树绑定。 ......第二个缺点是它们与UI的焦点树紧密相关并继续讨论CAL(Prism)包含的DelegateCommand和CompositeCommand。