通用/类型安全的ICommand实现?

时间:2011-06-08 00:18:32

标签: c# wpf generics mvvm .net-4.0

我最近开始使用WPF和MVVM框架,我想做的一件事就是拥有ICommand的类型安全实现,所以我不必抛出所有的命令参数。

有谁知道这样做的方法?

2 个答案:

答案 0 :(得分:14)

不使用该语法,正如您可能找到的那样:

  

错误CS0701:``System.Func`'不是有效约束。约束必须是接口,非密封类或类型参数

最好的办法是将Func<E,bool>语义封装在界面中,例如:

interface IFunctor<E>
{
   bool Execute(E value);
}

然后在类定义中使用此接口。虽然,我想知道你想要完成什么,因为可能有另一种方法解决你的问题。

根据@Alex正在寻找强类型ICommand实施的评论:

public FuncCommand<TParameter> : Command
{
    private Predicate<TParameter> canExecute;
    private Action<TParameter> execute;

    public FuncCommand(Predicate<TParameter> canExecute, Action<TParameter> execute)
    {
        this.canExecute = canExecute;
        this.execute = execute;
    }

    public override bool CanExecute(object parameter)
    {
        if (this.canExecute == null) return true;

        return this.canExecute((TParameter)parameter);
    }

    public override void Execute(object parameter)
    {
        this.execute((TParameter)parameter);
    }
}

像这样使用:

public class OtherViewModel : ViewModelBase
{
    public string Name { get; set; }
    public OtherViewModel(string name) { this.Name = name; }
}

public class MyViewModel : ViewModelBase
{
    public ObservableCollection<OtherViewModel> Items { get; private set; }
    public ICommand AddCommand { get; private set; }
    public ICommand RemoveCommand { get; private set; }

    public MyViewModel()
    {
        this.Items = new ObservableCollection<OtherViewModel>();

        this.AddCommand = new FuncCommand<string>(
            (name) => !String.IsNullOrEmpty(name),
            (name) => this.Items.Add(new OtherViewModel(name)));
        this.RemoveCommand = new FuncCommand<OtherViewModel>(
            (vm) => vm != null,
            (vm) => this.Items.Remove(vm));
    }
}

XAML:

<ListBox x:Name="Items" ItemsSource="{Binding Items}" />
<Button Content="Remove"
        Command="{Binding RemoveCommand}"
        CommandParameter="{Binding SelectedItem, ElementName=Items}" />
<StackPanel Orientation="Horizontal">
    <TextBox x:Name="NewName" />
    <Button Content="Add"
            Command="{Binding AddCommand}"
            CommandParameter="{Binding Text, ElementName=NewName}" />
</StackPanel>

我建议使用Microsoft的DelegateCommandRelayCommand,或其中任何一种的任何其他实现。

答案 1 :(得分:1)

您的命令类应订阅ICommand并定义CanExecuteChanged,如下所示。

public event EventHandler CanExecuteChanged
{
      add { CommandManager.RequerySuggested += value; }
      remove { CommandManager.RequerySuggested -= value; }
}