[英]Command in C# and WPF
我有非常简单的代码,但是它不起作用。
我有一个命令:
public class SetYesCommand : ICommand , INotifyPropertyChanged
{
public event EventHandler CanExecuteChanged;
public event PropertyChangedEventHandler PropertyChanged;
ViewModelBase view = new ViewModelBase();
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
view.Sname = "Yes";
MessageBox.Show("Command works");
onpropertychanged("Sname");
}
private void onpropertychanged(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
}
}
这是我的基本视图模型类:
public class ViewModelBase : INotifyPropertyChanged
{
private string _s;
public string Sname {
get { return _s; }
set { _s = value;
onPropertyChanged("Sname");
}
}
private void onPropertyChanged(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
这是我的XAML代码:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test"
mc:Ignorable="d"
xmlns:viewmodel="clr-namespace:Test.ViewModel"
xmlns:commands="clr-namespace:Test.ViewModel.Commands"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<viewmodel:ViewModelBase x:Key="base" ></viewmodel:ViewModelBase>
<viewmodel:Converters x:Key="convert" ></viewmodel:Converters>
<commands:SetYesCommand x:Key="setyes"/>
</Window.Resources>
<StackPanel>
<Button Width="100" Height="30" Command="{StaticResource setyes}"/>
<TextBox DataContext="{StaticResource base}" Text="{Binding Sname , Mode=TwoWay}"/>
<CheckBox DataContext="{StaticResource base}" IsChecked="{Binding Sname , Mode=TwoWay , Converter={StaticResource convert}}" />
<TextBox />
</StackPanel>
</Window>
如您所见,我将用户界面中的两个元素绑定到视图模型基类中的字符串属性,并且在用户界面中定义了按钮的命令。 该命令起作用的原因是,如您所见,我使用一个消息框对其进行了检查,但是UI中其他两个元素(文本框和复选框)的值未更改。
您正在SetYesCommand内创建ViewModelBase的新实例,因此view.Sname =“ Yes”不会更改绑定到元素的视图模型的Sname属性。
这正在工作:
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test"
mc:Ignorable="d"
xmlns:viewmodel="clr-namespace:Test.ViewModel"
xmlns:commands="clr-namespace:Test.ViewModel.Commands"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<viewmodel:ViewModelBase x:Key="base" ></viewmodel:ViewModelBase>
<viewmodel:Converters x:Key="convert" ></viewmodel:Converters>
</Window.Resources>
<StackPanel>
<Button Width="100" Height="30" Command="{Binding Source={StaticResource base},Path=YesCommand}"/>
<TextBox DataContext="{StaticResource base}" Text="{Binding Source={StaticResource base},Path=Sname , Mode=TwoWay}"/>
<CheckBox DataContext="{StaticResource base}" IsChecked="{Binding Sname , Mode=TwoWay , Converter={StaticResource convert}}" />
<TextBox />
</StackPanel>
</Window>
public class ViewModelBase : INotifyPropertyChanged
{
private string _s;
private Commands.SetYesCommand _yesCommand;
public ViewModelBase()
{
_yesCommand = new SetYesCommand(this);
}
public string Sname
{
get { return _s; }
set
{
_s = value;
onPropertyChanged("Sname");
}
}
public SetYesCommand YesCommand => _yesCommand;
private void onPropertyChanged(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class SetYesCommand : ICommand, INotifyPropertyChanged
{
public event EventHandler CanExecuteChanged;
public event PropertyChangedEventHandler PropertyChanged;
private ViewModelBase view;
public SetYesCommand(ViewModelBase view)
{
this.view = view;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
view.Sname = "Yes";
MessageBox.Show("Command works");
onpropertychanged("Sname");
}
private void onpropertychanged(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
}
您正在命令中创建ViewModelBase
的新实例。 视图模型应该创建命令,而不是相反。
ICommand
接口的典型实现通常接受要执行的Action<object>
和决定是否执行命令的Predicate<object>
:
public class SetYesCommand : ICommand
{
public event EventHandler CanExecuteChanged;
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public SetYesCommand(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)
{
if (_execute != null)
_execute(parameter);
}
}
然后在视图模型中实现该逻辑:
public class ViewModelBase : INotifyPropertyChanged
{
private string _s;
public string Sname
{
get { return _s; }
set
{
_s = value;
onPropertyChanged("Sname");
}
}
public ViewModelBase()
{
TheCommand = new SetYesCommand(OnCommandExecuted, null);
}
private void OnCommandExecuted(object parameter)
{
Sname = "Yes";
MessageBox.Show("Command works");
}
public ICommand TheCommand { get; private set; }
private void onPropertyChanged(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
在视图中,您绑定到视图模型的command属性,该属性返回ICommand
实现的实例:
<Button Width="100" Height="30" DataContext="{StaticResource base}" Command="{Binding TheCommand}"/>
您似乎对命令和视图模型之间的关系感到困惑。
命令对象应该是viewmodel的属性,而不是相反。
从基本的通用ICommand实现开始
public class BasicCommand: ICommand
{
private readonly Action _execute;
public BasicCommand(Action execute)
{
_execute = execute;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_execute?.Invoke();
}
public event EventHandler CanExecuteChanged;
}
比在您的viewmodel中,将命令定义为如下所示的属性
public class MyViewModel: ViewModelBase
{
public MyViewModel()
{
DoSomethingCommand = new BasicCommamd(()=>OnDoSomething());
}
public ICommand DoSomethingCommand {get;}
private void OnDoSomething()
{
// put whatever you want the command to do here
}
}
现在,您可以将Window的DataContext设置为MyViewModel的实例,并将按钮的command属性绑定到DoSomethingCommand。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.