代码之家  ›  专栏  ›  技术社区  ›  Mike Hofer

WPF架构混乱:路由命令、事件和手势

  •  2
  • Mike Hofer  · 技术社区  · 14 年前

    在学习WPF的过程中,我一直在阅读大量的书籍和网站。有一件事似乎一直在回避我,那就是我们应该如何正确地连接路由命令。在一篇文章中,作者指出,XAML文件的代码隐藏应该只包含对InitializeComponent的调用。我可以支持你。它使XAML文件只不过是一个演示文档,满足了我对分离关注点的邪恶渴望。

    另一方面,我看到的每个解决双击事件的示例似乎都希望您编写代码。据我所知,我们希望避免在codebhind文件中出现重复的代码(而且,我也完全赞成),所以在我看来,这不是正确的方法。菜单命令、工具栏按钮单击等等也是如此。

    例如,假设我有一个打开文档的命令。该命令必须显示“打开”对话框,然后打开文档并将其缓存在应用程序状态。(此应用程序只允许您一次处理一个文档。)用户可以通过以下任一方式调用此命令:

    • 从菜单中选择“文件”->“打开”。
    • 键入Ctrl+O。

    如果我信任Web上的大多数源,我必须编写至少两个单击事件处理程序,然后调用该命令,从而污染代码隐藏文件。在我看来,这似乎是为了挫败掌握命令的目的。我 思想

    有人能给我解释一下吗?在这一点上,一切都开始看起来像巫毒和弹片。

    2 回复  |  直到 14 年前
        1
  •  2
  •   Robert Jeppesen    14 年前

    在WPF中进行命令是相当麻烦的,但它确实解决了为您更新IsEnabled的问题。这是典型的例子。步骤1是可选的,因为有很多 built-in common commands 以减少锅炉板的数量。

    第一步。(可选)在静态类中创建命令

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows.Input;
    
    namespace WpfApplication1
    {
       public static class Commands
       {
          public static RoutedCommand WibbleCommand = new RoutedUICommand
          (
             "Wibble",
             "Wibble",
             typeof(Commands),
             new InputGestureCollection()
                {
                   new KeyGesture(Key.O, ModifierKeys.Control)
                }
          );
       }
    }
    

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
       <Window.CommandBindings>
          <CommandBinding
             Command="{x:Static local:Commands.WibbleCommand}"
             Executed="WibbleCommandExecuted"
             CanExecute="WibbleCommandCanExecute"
          />
       </Window.CommandBindings>
    

    第三步:连接控件(菜单项、按钮等)

    这里的长绑定是为了纠正Button默认情况下不使用命令文本这一事实。

      <Button Command="{x:Static local:Commands.WibbleCommand}" Width="200" Height="80">
         <TextBlock Text="{Binding Path=Command.Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}">
         </TextBlock>
      </Button>
    

    步骤4:在代码隐藏中实现Execute和CanExecute的处理程序

    小心点!这将被称为非常经常,所以尽量不要做任何昂贵的在这里。

      private void WibbleCommandExecuted(object sender, ExecutedRoutedEventArgs e)
      {
         MessageBox.Show("Wibbled!");
      }
    
      private void WibbleCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
      {
         e.CanExecute = DateTime.Now.Minute % 2 == 0;
      }
    
        2
  •  4
  •   Ian Griffiths    14 年前

    在这个习惯用法中,您几乎从不使用ApplicationCommands.Open这样的内置命令。这些东西的唯一真正用途是,如果您希望对焦点敏感的命令本质上由控件处理。E、 例如,文本框内置了编辑、复制、粘贴等命令处理。这避免了代码隐藏的问题,因为它是一个完整的自定义控件,而且自定义控件并没有真正的代码隐藏——它们都是代码。(Xaml实际上位于一个完全独立的对象、模板中,并不是控件的一部分。)无论如何,它不是您的代码-您有一个已经知道如何支持该命令的控件,因此您可以完全保留在这里的Xaml中。

    命令路由在这个特定的场景中很有趣,因为它允许您放置一组与各种编辑控件相关联的菜单项,路由系统根据焦点所在的位置确定哪个文本框(或任何内容)将处理命令。如果这不是您想要的,那么命令路由可能对您没有多大用处。

    然而,这里有一个更大的问题,当你发现你真的必须把代码放在代码后面时该怎么做。如果使用自定义ICommand实现(尽管有奇怪的异常),命令通常不是该场景的示例,但用户输入事件稍微有趣一些。你提到了双击,但是,如果你正在做任何一种不寻常的互动,你往往想要像鼠标上下等东西。

    在本例中,通常的方法是咬紧牙关,将代码放在codebhind中,但您尝试将其保持为每个事件处理程序一行。基本上,您的代码隐藏只是调用viewmodel上的相关方法,这才是真正处理事件的方法。

    推荐文章