【问题标题】:Custom WPF command pattern example自定义 WPF 命令模式示例
【发布时间】:2010-09-05 17:25:13
【问题描述】:

我已经完成了一些 WPF 编程,但我从未得到过的一件事是命令模式。每个示例似乎都是内置的,编辑、剪切、粘贴。任何人都有自定义命令的最佳实践示例或建议?

【问题讨论】:

    标签: wpf design-patterns command


    【解决方案1】:

    啊哈!一个我可以回答的问题!首先,我应该提到,我个人发现在代码中定义和连接命令比在 XAML 中更容易。它允许我比所有 XAML 方法更灵活地连接命令的处理程序。

    您应该弄清楚您想要拥有哪些命令以及它们与什么相关。在我的应用程序中,我目前有一个用于定义重要应用程序命令的类,如下所示:

    public static class CommandBank
    {
      /// Command definition for Closing a window
      public static RoutedUICommand CloseWindow { get; private set; }
    
      /// Static private constructor, sets up all application wide commands.
      static CommandBank()
      {
        CloseWindow = new RoutedUICommand();
        CloseWindow.InputGestures.Add(new KeyGesture(Key.F4, ModifierKeys.Alt));
        // ...
      }
    

    现在,因为我想将所有代码放在一起,所以对命令使用仅代码方法可以让我将以下方法放在上面的类中:

    /// Closes the window provided as a parameter
    public static void CloseWindowExecute(object sender, ExecutedRoutedEventArgs e)
    {
      ((Window)e.Parameter).Close();
    }
    
    /// Allows a Command to execute if the CommandParameter is not a null value
    public static void CanExecuteIfParameterIsNotNull(object sender, CanExecuteRoutedEventArgs e)
    {
      e.CanExecute = e.Parameter != null;
      e.Handled = true;
    }
    

    那里的第二种方法甚至可以与其他命令共享,而无需我在整个地方重复。

    一旦您定义了这样的命令,您就可以将它们添加到任何 UI 中。在下文中,一旦加载了 Window,我将命令绑定添加到 Window 和 MenuItem,然后使用循环将输入绑定添加到 Window 以对所有命令绑定执行此操作。传递的参数是 Window 本身,因此上面的代码知道要尝试关闭哪个 Window。

    public partial class SimpleWindow : Window
    {
      private void WindowLoaded(object sender, RoutedEventArgs e)
      {
        // ...
        this.CommandBindings.Add(
          new CommandBinding(
            CommandBank.CloseWindow,
            CommandBank.CloseWindowExecute,
            CommandBank.CanExecuteIfParameterIsNotNull));
    
        foreach (CommandBinding binding in this.CommandBindings)
        {
           RoutedCommand command = (RoutedCommand)binding.Command;
           if (command.InputGestures.Count > 0)
           {
             foreach (InputGesture gesture in command.InputGestures)
             {
               var iBind = new InputBinding(command, gesture);
               iBind.CommandParameter = this;
               this.InputBindings.Add(iBind);
             }
           }
        }
    
        // menuItemExit is defined in XAML
        menuItemExit.Command = CommandBank.CloseWindow;
        menuItemExit.CommandParameter = this;
        // ...
      }
    
      // ....
    }
    

    我后来也有 WindowClosing 和 WindowClosed 事件的事件处理程序,我建议您使命令的实际实现尽可能小和通用。在这种情况下,如果有未保存的数据,我没有尝试放置试图停止窗口关闭的代码,而是将该代码牢牢地保存在 WindowClosing 事件中。

    如果您有任何后续问题,请告诉我。 :)

    【讨论】:

    • 您的 CanExecuteIfParameterIsNotNull 包含我的宠物烦恼之一。为什么不只是 e.CanExecute = e.Parameter != null;
    • @Ray 这不是我知道我能做到的!感谢您的编辑德鲁。 :)
    【解决方案2】:

    【讨论】:

    【解决方案3】:

    在 2008 年 9 月版的 MSDN 杂志中,Brian Noyes 有一篇关于 RoutedCommand/RoutedEvents 的优秀文章!!!

    这里是链接: http://msdn.microsoft.com/en-us/magazine/cc785480.aspx

    【讨论】:

      【解决方案4】:

      XAML 的优点是它适用于“简单”程序,但遗憾的是,当您想要执行共享功能之类的事情时,它就不能很好地工作。假设您有几个类和 UI,所有这些类和 UI 都具有从未禁用的命令,您必须为每个 Window 或 UserControl 编写一个“CanAlwaysExecute”方法!那不是很DRY

      阅读了几篇博客并尝试了几件事后,我决定让 XAML 纯粹与外观、样式、动画和触发器有关。我所有的事件处理程序和命令连接现在都在代码隐藏中。 :)

      另一个问题是输入绑定,为了让它们被捕获,焦点必须放在包含输入绑定的对象上。例如,要获得可以随时使用的快捷方式(例如,F1 打开帮助),必须在 Window 对象上设置输入绑定,因为当您的应用程序处于活动状态时,它始终具有焦点。使用 code 方法应该会更容易,即使您开始使用可能希望将输入绑定添加到其父窗口的 UserControl。

      【讨论】:

        猜你喜欢
        • 2011-07-18
        • 1970-01-01
        • 1970-01-01
        • 2010-12-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-08
        相关资源
        最近更新 更多