【问题标题】:WPF using custom RoutedUICommands or simple event handlers?WPF 使用自定义 RoutedUICommands 还是简单的事件处理程序?
【发布时间】:2010-10-08 04:23:14
【问题描述】:

我今天与某人讨论如何选择一种设计模式来处理他们的 WPF 程序中的逻辑,并希望 SO 社区可以提供进一步的建议以使决策更容易。 哪些因素有利于命令胜过不便?

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

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

他参加的入门课程和许多书籍都将简单的 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

【问题讨论】:

  • “哪些因素有利于命令胜过不便?”对我来说似乎是一个问题。我认为背景的数量可能会让人们更容易看出我是认真的并理解上下文。

标签: wpf xaml routed-commands


【解决方案1】:

命令各有优劣,你要根据自己的情况来选择, 我强烈建议您根据具体情况做出选择,不要为整个项目选择“一种真正的方式”。

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

在其他情况下,命令可以将原本只有 2 行的事件处理程序变成一些无法跟踪的怪物,涉及更改应用程序中的 4 个不同位置 (How should the ViewModel close the form?)。

【讨论】:

    【解决方案2】:

    唯一的原因是要熟悉命令注册表。意味着事件可能是私有方法,我觉得它们与窗口的代码紧密结合。同时 Commands 提供了将实现(事件)和定义(命令)分开的能力,你甚至可以使用另一个类(看看 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}" />
    

    【讨论】:

      【解决方案3】:

      在开发 WPF 应用程序时,我尝试忠实于 Mike 在开发 WPF 应用程序时提到的命令模式,并结合使用了 Andy 的 #2 和 #3 方法。

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

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

      【讨论】:

        【解决方案4】:

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

        Brian Noyes 在他的article on PRISM 中说

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多