代码之家  ›  专栏  ›  技术社区  ›  Brian Leahy

自定义WPF命令模式示例

  •  36
  • Brian Leahy  · 技术社区  · 18 年前

    我做过一些WPF编程,但有一件事我从来没有得到过,那就是命令模式。每个例子似乎都是内置的,编辑,剪切,粘贴。有人对自定义命令的最佳实践有什么样的例子或建议吗?

    4 回复  |  直到 10 年前
        1
  •  38
  •   Drew Noakes    17 年前

    啊哈!一个我能回答的问题!首先,我应该提到,我个人发现在代码中定义和连接命令比在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中。在下面的示例中,一旦加载了窗口,我将向窗口和MenuItem添加命令绑定,然后使用循环向窗口添加输入绑定,以对所有命令绑定执行此操作。传递的参数是窗口本身,因此上面的代码知道尝试关闭哪个窗口。

    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事件中。

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

        3
  •  4
  •   rudigrobler    18 年前

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

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

        4
  •  3
  •   VolkerK    18 年前

    XAML的优点是,它适用于“简单”程序,但遗憾的是,当您想要执行诸如共享函数之类的操作时,它不能很好地工作。假设您有几个类和UI,它们都有从未禁用过的命令,那么您必须为每个窗口或用户控件编写一个“CanAlwaysExecute”方法!那不是很好 .

    在阅读了几篇博客并尝试了几件事情之后,我选择了让XAML只关注外观、样式、动画和触发器。我所有的事件处理程序连接和命令现在都在代码隐藏中完成了。:)

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

    推荐文章