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

时间:2021-10-03 16:26:07

I was talking to someone today about picking a design pattern for how to handle logic in their WPF program and hoping that the SO community can help with further advice to make the decision easier. What factors in favour of commands outweigh the inconvenience?

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

I prepared a full sample along with some UML diagrams of the first two of three approaches:

我准备了一个完整的示例以及前三种方法的一些UML图:

  1. Use Click event handlers on buttons and menus.
  2. 在按钮和菜单上使用Click事件处理程序。

  3. Use commands bound in XAML.
  4. 使用XAML中绑定的命令。

  5. Use commands bound in code, with the XAML kept for pure GUI layout and styling.
  6. 使用绑定在代码中的命令,保留XAML以实现纯GUI布局和样式。

The introductory course he'd been on and many of the books show simple Click event handlers as the natural way to connect logic to UI objects.

他上过的入门课程和许多书籍都展示了简单的Click事件处理程序,作为将逻辑连接到UI对象的自然方式。

He was a bit stunned by the amount of overhead required to use commands with both the command being created in the code behind file:

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

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

and then even more code in the XAML with the wordy way the command has to be identified and bound:

然后在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>

I can't (yet) claim to be a WPF expert so I may have painted things as more complex than they really are but my suspicion is that you can't simplify things much more than the above.

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

Edit:

I found an interesting 3-way comparison between DelegateCommand, RoutedCommand and Event.

我在DelegateCommand,RoutedCommand和Event之间找到了一个有趣的三向比较。

4 个解决方案

#1


6  

Commands their advantages and disadvantages, you have to choose based on your situation, I highly recommend you make that choice on a case basis, don't choose "the one true way" for the entire project.

命令它们的优点和缺点,你必须根据你的情况选择,我强烈建议你在一个案例的基础上做出选择,不要为整个项目选择“一个真正的方法”。

For some cases the separation between sender and receiver and the ability to send commands using only XAML is a big advantage (for a good example look how the ScrollBar control template communicates with the control logic at http://msdn.microsoft.com/en-us/library/ms742173.aspx ).

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

In other cases commands can turn what would have been a 2 lines event handler into some impossible to follow monstrosity involving changing 4 separate places in the application (How should the ViewModel close the form? ).

在其他情况下,命令可以将本来是2行事件处理程序变成一些不可能跟随怪物,包括更改应用程序中的4个单独位置(ViewModel应该如何关闭表单?)。

#2


3  

The only reason is to have well know registry of commands. Means that events are likely to be private methods and I feel that they are tightly bonded to code of the window. At the same time Commands gives ability to keep implementation (event) and definition (Command) separately, you can even use another class (take a look on ApplicationCommands).

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

In addition, when I am doing my WPF work I use implementation of the ICommand(Command Pattern). All logic of the command goes to the Execute method. This helps me to keep separation of logic in more structured way witout overcomplication of the window code. With this option you can create commands on your model and therefore bind them witout noise. Take a look.

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

Create model.

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

Then assign Data Context

然后分配数据上下文

public MainWindow()
{

  this.DataContext = new Model();
}

And use follwing XAML code.

并使用以下XAML代码。

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

#3


2  

I try to stay true to the command pattern that Mike refers to when developing WPF applications, using a combination of Andy's #2 and #3 approaches.

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

I can think of only one downside of commands in my view: only certain actions of certain UI elements invoke commands. One way to get around this is to have your event handler call the Execute method on a command. I think that commands provide a very good way to encapsulate execution logic. If you maintain a large piece of UI and implement it using a MVC/MVC/MVVM pattern, this becomes very apparent.

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

I encourage you to take a look at Dan Crevier's series on the DataModel-View-ViewModel pattern, in particular the section on Commands and Encapsulating Commands. Even if this pattern doesn't meet your needs, it gives a great overview of how you can encapsulate logic inside a separate class.

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

#4


1  

Other variations on ICommand seem to be a popular way to implement complex command structures.

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

Brian Noyes in his article on PRISM says

Brian Noyes在他关于PRISM的文章中说

Routed commands in WPF are very powerful and useful, but they have some shortcomings when applied to a composite application. The first is that they are entirely coupled to the visual tree-the invoker has to be part of the visual tree, and the command binding has to be tied in through the visual tree. ... The second shortcoming is that they are tightly tied in with the focus tree of the UI and goes on to talk about the DelegateCommand and CompositeCommand which CAL (Prism) includes.

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

#1


6  

Commands their advantages and disadvantages, you have to choose based on your situation, I highly recommend you make that choice on a case basis, don't choose "the one true way" for the entire project.

命令它们的优点和缺点,你必须根据你的情况选择,我强烈建议你在一个案例的基础上做出选择,不要为整个项目选择“一个真正的方法”。

For some cases the separation between sender and receiver and the ability to send commands using only XAML is a big advantage (for a good example look how the ScrollBar control template communicates with the control logic at http://msdn.microsoft.com/en-us/library/ms742173.aspx ).

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

In other cases commands can turn what would have been a 2 lines event handler into some impossible to follow monstrosity involving changing 4 separate places in the application (How should the ViewModel close the form? ).

在其他情况下,命令可以将本来是2行事件处理程序变成一些不可能跟随怪物,包括更改应用程序中的4个单独位置(ViewModel应该如何关闭表单?)。

#2


3  

The only reason is to have well know registry of commands. Means that events are likely to be private methods and I feel that they are tightly bonded to code of the window. At the same time Commands gives ability to keep implementation (event) and definition (Command) separately, you can even use another class (take a look on ApplicationCommands).

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

In addition, when I am doing my WPF work I use implementation of the ICommand(Command Pattern). All logic of the command goes to the Execute method. This helps me to keep separation of logic in more structured way witout overcomplication of the window code. With this option you can create commands on your model and therefore bind them witout noise. Take a look.

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

Create model.

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

Then assign Data Context

然后分配数据上下文

public MainWindow()
{

  this.DataContext = new Model();
}

And use follwing XAML code.

并使用以下XAML代码。

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

#3


2  

I try to stay true to the command pattern that Mike refers to when developing WPF applications, using a combination of Andy's #2 and #3 approaches.

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

I can think of only one downside of commands in my view: only certain actions of certain UI elements invoke commands. One way to get around this is to have your event handler call the Execute method on a command. I think that commands provide a very good way to encapsulate execution logic. If you maintain a large piece of UI and implement it using a MVC/MVC/MVVM pattern, this becomes very apparent.

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

I encourage you to take a look at Dan Crevier's series on the DataModel-View-ViewModel pattern, in particular the section on Commands and Encapsulating Commands. Even if this pattern doesn't meet your needs, it gives a great overview of how you can encapsulate logic inside a separate class.

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

#4


1  

Other variations on ICommand seem to be a popular way to implement complex command structures.

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

Brian Noyes in his article on PRISM says

Brian Noyes在他关于PRISM的文章中说

Routed commands in WPF are very powerful and useful, but they have some shortcomings when applied to a composite application. The first is that they are entirely coupled to the visual tree-the invoker has to be part of the visual tree, and the command binding has to be tied in through the visual tree. ... The second shortcoming is that they are tightly tied in with the focus tree of the UI and goes on to talk about the DelegateCommand and CompositeCommand which CAL (Prism) includes.

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