我是WPF和c#的新手。我正在阅读有关Command Design Pattern的内容,并期待在我的新应用程序上实现它,以便它可以执行和撤消功能。然后我意识到WPF已经附带了一个ICommand接口,并且de xml按钮可以实现它。所述界面有这样的方法:
public bool CanExecute(object parameter)
{
}
private void OnCanExecuteChanged()
{
}
public void Execute(object parameter)
{
}
那么,我是否应该通过从其中继承一些其他接口并添加撤消方法来将撤消功能添加到已经内置在ICommand接口中的撤消功能?
这个界面只适用于按钮吗?我的意思是,我想创建许多其他命令,这些命令不是necesarilly连接到xnml按钮
提前致谢!
首先,这些命令是MVVM模式的一部分,您应该首先阅读它。
C#中的接口不提供任何功能,它们仅描述继承此接口的类应该如何工作。如果您希望班级做某事,您不应该将这些方法留空。
WPF中的命令代表了一种稍后将传输逻辑的框架。命令的最合理用途是将它们绑定到按钮。
ICommand实现示例:
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private readonly Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged {
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute == null || canExecute(parameter);
}
public void Execute(object parameter)
{
execute(parameter);
}
}
命令使用示例:
public static RelayCommand NavigateToSignInPage => new RelayCommand(
actionParameter => Application.Instance.Navigation.NavigateTo(new LoginForm()));
public static RelayCommand NavigateToSignUpPage => new RelayCommand(
actionParameter => Application.Instance.Navigation.NavigateTo(new RegistrationForm()));
public static RelayCommand NavigateToStartPage => new RelayCommand(
actionParameter => Application.Instance.Navigation.NavigateTo(new StartPage()));
public static RelayCommand NavigateBack => new RelayCommand(
actionParameter => Application.Instance.Navigation.NavigateBack(),
actionPossibilityParameter => Application.Instance.Navigation.BackNavigationPossible);
命令绑定示例:在视图(xaml)中:
<Button x:Name="CancelButton"
Content="Cancel"
Command="{Binding CancelCommand}"
Grid.Row="2"
IsCancel="True"
HorizontalAlignment="Left"
Margin="44,0,0,0"
Width="118" Height="23"
VerticalAlignment="Center" />
在ViewModel中:
public RelayCommand CancelCommand => NavigationCommands.NavigateBack;
CanExecute
将引导您是否执行命令,对于Command实现,您可以看到here。我觉得你在这里混淆了不同的事情。 ICommand Interface
用于将UI事件绑定到MVVM等设计模式中使用的代码。您尝试实施的Command Design Pattern
是undoing actions的状态架构,如按钮按下。
许多答案突出了使用委托的ICommand接口的有用实现。您甚至可以通过绑定到如下所示的模型更改来进一步操作,或者如果您愿意,可以随意过滤。这可以用于重新评估命令是否应该能够基于模型状态触发,因为这直接与按钮的“启用”状态相关联。
public class ObservableCommand<T> : ICommand where T : System.ComponentModel.INotifyPropertyChanged
{
Predicate<object> _predicate;
Action<object> _execute;
public ObservableCommand(T model, Action<object> execute, Predicate<object> predicate)
{
model.PropertyChanged += ModelChanged;
_execute = execute;
_predicate = predicate;
}
public event EventHandler CanExecuteChanged;
private void ModelChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
public bool CanExecute(object parameter)
{
return _predicate(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
关于撤消操作的问题。您当然可以使用命令来调用它,但是跟踪对象的状态是更棘手的部分。您可以使用memento design pattern并将命令绑定到恢复状态功能。这是过于简单化,但一直是我过去所做的实施的核心。
public class Memento<T>
{
public Memento(T startState)
{
this.State = startState;
this.OriginalState = startState;
}
public T State { get; set; }
public T OriginalState { get; }
public void RestorOriginalState()
{
State = OriginalState;
}
}