[英]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.