实现自定义 WPF 命令

3

我想实现一个自定义 WPF 命令,于是搜索并找到了以下代码:

public static class CustomCommands
{
    public static readonly RoutedUICommand Exit = new RoutedUICommand
    (
        "Exit",
        "Exit",
        typeof(CustomCommands),
        new InputGestureCollection()
        {
            new KeyGesture(Key.F4, ModifierKeys.Alt)
        }
    );

    //Define more commands here, just like the one above
}


我有两个问题不是很清楚。

  1. 是否有必要使用命令 static readonly?我们能否只使用 const 来声明呢?

  2. new InputGestureCollection() { new KeyGesture(Key.F4, ModifierKeys.Alt) } 到底是什么?如果它正在调用默认构造函数并初始化属性,那么应该有属性可以分配,但实际上没有。 InputGestureCollection 有大括号,但在大括号内部没有初始化任何属性。这是怎么回事?这是什么类型的语句?

2个回答

8
首先,您需要对WPF和MVVM有一些基本的了解。 您有一个类,将要绑定到UI上。该类不是.xaml.cs文件。
它完全独立于视图。您需要将该类的实例放入窗口的DataContext中,可以通过在.xaml.cs中调用类似于以下内容的代码来实现:
this.DataContext = new MyViewModel();

现在,你的 MyViewModel 类需要一个类型为 ICommand 的属性。最佳实践是创建一个实现了 ICommand 接口的类。通常称之为 DelegateCommand 或 RelayCommand。例如:

public class DelegateCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public DelegateCommand(Action<object> execute,
                   Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecute == null)
        {
            return true;
        }

        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }
}

然后在你的ViewModel中创建一个带有该类实例的属性。像这样:

public class MyViewModel{

   public DelegateCommand AddFolderCommand { get; set; }
   public MyViewModel(ExplorerViewModel explorer)
   {           
       AddFolderCommand = new DelegateCommand(ExecuteAddFolderCommand, (x) => true);
   }

   public void ExecuteAddFolderCommand(object param)
   {          
       MessageBox.Show("this will be executed on button click later");
   }
}

在您的视图中,现在可以将按钮的命令绑定到该属性。

<Button Content="MyTestButton" Command="{Binding AddFolderCommand}" />

一个路由命令是指框架中默认存在的东西(如复制、粘贴等)。如果你是MVVM的初学者,在掌握“普通”命令的基本理解之前,不应该考虑创建路由命令。
回答你的第一个问题:将命令设置为静态和/或常量绝对不是必要的。(请参见MyViewModel类)
你的第二个问题:你可以使用默认值初始化列表,将其放入{ }括号中。例如:
var Foo = new List<string>(){ "Asdf", "Asdf2"};

您没有一个您初始化属性的对象。您有一个列表,您在其中进行初始化,然后使用您放入{括号中的参数调用Add()

这也是您的情况基本发生的事情。您有一个集合,您使用一些值进行初始化。


你对第一个问题一点都不知道吗?这个问题重要吗? - Green Falcon
@media 请再次查看答案。 - Dominik
这里需要使用谓词吗?还是我可以用 Func 来替换它? - Leon Bohmann
1
@LeonBohmann 你可以按照自己的喜好实现这个类。给出的只是一个经常使用的例子。只要你成功地实现了 ICommand 接口,就没问题了。 - Dominik
1
顺便说一下:Predicate<T> 基本上与 Func<T,bool> 相同。 - Dominik
@Dominik 谢谢。这就是我一直不确定的事情。 - Leon Bohmann

1
回答您的第二个问题:

new InputGestureCollection()
{
    new KeyGesture(Key.F4, ModifierKeys.Alt)
}

这是一个集合初始化器的示例,等价于:
var collection = new InputGestureCollection();
collection.Add(new KeyGesture(Key.F4, ModifierKeys.Alt));

这只是一个速记法,也是ReSharper建议的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接