I recently started using WPF and the MVVM framework, one thing that I have wanted to do is to have a type safe implementation of ICommand
so I do not have to cast all the command paramaters.
Does anyone know of a way to do this?
Not using that syntax, as you probably found:
error CS0701: ``System.Func`' is not a valid constraint. A constraint must be an interface, a non-sealed class or a type parameter
Your best bet is to encapsulate the Func<E,bool>
semantics in an interface, like:
interface IFunctor<E>
{
bool Execute(E value);
}
and then use this interface in the class definition. Although, I am wondering what you're looking to accomplish as there may be another approach to your problem.
Per the comment that @Alex is looking for a strongly typed ICommand
implementation:
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);
}
}
Used like so:
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>
I would recommend using Microsoft's DelegateCommand or RelayCommand, or any other implementation of either of these.
Your command class should subscribe to ICommand and define the CanExecuteChanged as below.
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With