代码之家  ›  专栏  ›  技术社区  ›  Andy Dent

使用自定义RouteDuiCommands或简单事件处理程序的WPF?

  •  5
  • Andy Dent  · 技术社区  · 15 年前

    今天我和某人讨论了如何在他们的WPF程序中选择一个设计模式来处理逻辑,并希望SO社区能够帮助提供进一步的建议,使决策更容易。 哪些因素有利于指挥,而非不便?

    我准备了一个完整的 sample 连同一些 UML diagrams 三种方法中的前两种:

    1. 在按钮和菜单上使用单击事件处理程序。
    2. 使用XAML中绑定的命令。
    3. 使用在代码中绑定的命令,将XAML保留为纯GUI布局和样式。

    他上的入门课程和许多书都将简单的单击事件处理程序作为将逻辑连接到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专家,所以我可能把事情画得比实际情况更复杂,但我的怀疑是,你不能把事情简化得比上面多。

    编辑:

    我发现一个有趣的 3-way comparison 在delegatecommand、routedcommand和event之间。

    4 回复  |  直到 15 年前
        1
  •  6
  •   Community Ian Goodfellow    7 年前

    掌握他们的优势和劣势,你必须根据自己的情况来选择, 我强烈建议您根据具体情况做出选择,不要为整个项目选择“唯一正确的方法”。

    在某些情况下,发送方和接收方之间的分离以及仅使用XAML发送命令的能力是一个很大的优势(对于一个很好的示例,请看滚动条控件模板如何与位于 http://msdn.microsoft.com/en-us/library/ms742173.aspx )

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

        2
  •  3
  •   Mike Chaliy    15 年前

    唯一的原因是拥有熟悉的命令注册表。这意味着事件可能是私有方法,我觉得它们与窗口代码紧密地绑定在一起。同时,命令提供了将实现(事件)和定义(命令)分开的能力,您甚至可以使用另一个类(查看applicationcommands)。

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

    创建模型。

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

    然后分配数据上下文

    public MainWindow()
    {
    
      this.DataContext = new Model();
    }
    

    并使用以下XAML代码。

    <Button 
        Command="{Binding CloseMessagePopupCommand}"
        Content="{StaticResource Misc.Ok}" />
    
        3
  •  2
  •   Szymon Rozga    15 年前

    在开发WPF应用程序时,我尝试遵循Mike所指的命令模式,使用Andy's 2和3方法的组合。

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

    我鼓励你看看丹·克里维尔的系列 DataModel-View-ViewModel 模式,特别是关于命令和封装命令的部分。即使这个模式不满足您的需求,它也提供了如何在一个单独的类中封装逻辑的一个很好的概述。

        4
  •  1
  •   Andy Dent    15 年前

    ICommand上的其他变体似乎是实现复杂命令结构的常用方法。

    布莱恩·诺伊斯 article on PRISM

    WPF中的路由命令非常强大和有用,但是在应用于复合应用程序时它们有一些缺点。首先,它们完全耦合到可视化树,调用程序必须是可视化树的一部分,并且命令绑定必须通过可视化树进行绑定。…第二个缺点是它们与UI的焦点树紧密相连。 然后继续讨论cal(prism)包含的delegatecommand和computecommand。