C# 如何处理MVVM模式中的多个复选框?
WPF中的绑定复选框是一个常见问题,但我仍然没有找到初学者容易理解的示例代码。我在WPF中有复选框列表来选择最喜爱的运动的名称。在我的例子中,复选框的数量是静态的。有人能告诉我如何实现这个问题的ViewModel吗 FavoriteSportsView.xaml:C# 如何处理MVVM模式中的多个复选框?,c#,wpf,xaml,mvvm,checkbox,C#,Wpf,Xaml,Mvvm,Checkbox,WPF中的绑定复选框是一个常见问题,但我仍然没有找到初学者容易理解的示例代码。我在WPF中有复选框列表来选择最喜爱的运动的名称。在我的例子中,复选框的数量是静态的。有人能告诉我如何实现这个问题的ViewModel吗 FavoriteSportsView.xaml: <StackPanel Height="50" HorizontalAlignment="Left" VerticalAlignment="Top" Width="150"> <CheckBox Is
<StackPanel Height="50" HorizontalAlignment="Left" VerticalAlignment="Top"
Width="150">
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}"
CommandParameter="Football"
Content="Football"
Margin="5" />
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}"
CommandParameter="Hockey"
Content="Hockey"
Margin="5" />
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}"
CommandParameter="Golf"
Content="Golf"
Margin="5" />
</StackPanel>
我不确定如何在上述ViewModel中执行以下操作:
1.如何实现单个方法来处理所有选项?
2.如何检测每个复选框以查看是否选中
3.如何使用CommandParameter?
4.如何正确实现SportsResponseCommand如果您只想在检查
时更新ViewModel中的属性,请将检查的绑定替换为ViewModel中的布尔属性,该属性在其“集合”上引发NotifyPropertyChanged
现在,如果您想在每次检查3个复选框之一时执行操作:
首先,将CommandParameter替换为“{Binding RelativeSource={RelativeSource Mode=Self}}”
在ViewModel(应实现INotifyPropertyChanged)中,创建一个ICommand(SportsResponseCommand),该命令在参数中包含一个复选框
在命令的方法中,检查复选框的内容,以及“IsChecked”属性,然后对它们进行处理
如果您还有其他问题,请告诉我。如果您只想在检查时更新ViewModel中的属性,请将检查的绑定替换为ViewModel中的布尔属性,该属性在其“集合”上引发NotifyPropertyChanged
现在,如果您想在每次检查3个复选框之一时执行操作:
首先,将CommandParameter替换为“{Binding RelativeSource={RelativeSource Mode=Self}}”
在ViewModel(应实现INotifyPropertyChanged)中,创建一个ICommand(SportsResponseCommand),该命令在参数中包含一个复选框
在命令的方法中,检查复选框的内容,以及“IsChecked”属性,然后对它们进行处理
如果您还有其他问题,请告诉我。您的视图模型应该如下所示:
public class MyViewModel : INotifyPropertyChanged
{
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
//bindable property
private bool _football;
public bool Football
{
get { return _football; }
set
{
if (value != _football)
{
_football = value;
this.OnPropertyChanged("Football");
}
}
}
//... and the same for Golf and Hockey
}
然后通过设置DataContext
属性将视图模型与视图关联起来(这很可能在窗口中
或UserControl
代码隐藏中,尽管有很多方法可以实现)
最后,更新绑定,使其看起来像:
<CheckBox IsChecked="{Binding Football, Mode=TwoWay}"
Content="Football"
Margin="5" />
<CheckBox IsChecked="{Binding Golf, Mode=TwoWay}"
Content="Football"
Margin="5" />
最后,您不需要绑定命令
属性-您只需编写需要在视图模型的属性设置程序中运行的任何代码。您的视图模型应该如下所示:
public class MyViewModel : INotifyPropertyChanged
{
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
//bindable property
private bool _football;
public bool Football
{
get { return _football; }
set
{
if (value != _football)
{
_football = value;
this.OnPropertyChanged("Football");
}
}
}
//... and the same for Golf and Hockey
}
然后通过设置DataContext
属性将视图模型与视图关联起来(这很可能在窗口中
或UserControl
代码隐藏中,尽管有很多方法可以实现)
最后,更新绑定,使其看起来像:
<CheckBox IsChecked="{Binding Football, Mode=TwoWay}"
Content="Football"
Margin="5" />
<CheckBox IsChecked="{Binding Golf, Mode=TwoWay}"
Content="Football"
Margin="5" />
最后,您不应该真正需要绑定命令
属性-您只需编写在视图模型的属性设置器中运行所需的任何代码。您可以使用此命令指定视图模型
//for the view
partial class MainView:Window
{
InitializeComponent();
this.DataContext=new MainViewModel();
}
//ViewModel Code
public class MainViewModel: INotifyPropertyChanged
{
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
//bindable property
private bool _football;
public bool Football
{
get { return _football; }
set
{
if (value != _football)
{
_football = value;
this.OnPropertyChanged("Football");
}
}
}
//... and the same for Golf and Hockey
}`
然后可以在XAML中实现绑定,如下所示
您可以使用以下命令指定视图模型
//for the view
partial class MainView:Window
{
InitializeComponent();
this.DataContext=new MainViewModel();
}
//ViewModel Code
public class MainViewModel: INotifyPropertyChanged
{
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
//bindable property
private bool _football;
public bool Football
{
get { return _football; }
set
{
if (value != _football)
{
_football = value;
this.OnPropertyChanged("Football");
}
}
}
//... and the same for Golf and Hockey
}`
然后可以在XAML中实现绑定,如下所示
我强烈建议您阅读此
我在下面描述了一个解决方案,我试图不修改您的XAML代码,但这不是唯一的方法(或最佳方法),而是包含所有必要的元素
第一步你们需要你们的模型,我称之为模型运动
public class Model_Sport : INotifyPropertyChanged
{
#region Constructor
public Model_Sport(string name, ICommand command)
{
Name = name;
SportsResponseCommand = command;
}
#endregion
static readonly PropertyChangedEventArgs _NameEventArgs = new PropertyChangedEventArgs("Name");
private string _Name = null;
public string Name
{
get { return _Name; }
set
{
_Name = value;
OnPropertyChanged(_NameEventArgs);
}
}
static readonly PropertyChangedEventArgs _SportsResponseCommandEventArgs = new PropertyChangedEventArgs("SportsResponseCommand");
private ICommand _SportsResponseCommand = null;
public ICommand SportsResponseCommand
{
get { return _SportsResponseCommand; }
set
{
_SportsResponseCommand = value;
OnPropertyChanged(_SportsResponseCommandEventArgs);
}
}
static readonly PropertyChangedEventArgs _IsCheckedEventArgs = new PropertyChangedEventArgs("IsChecked");
private bool _IsChecked = false;
public bool IsChecked
{
get { return _IsChecked; }
set
{
_IsChecked = value;
OnPropertyChanged(_IsCheckedEventArgs);
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
{
if (PropertyChanged != null)
{
PropertyChanged(this, eventArgs);
}
}
#endregion
}
现在您需要一种方法来委托您的命令“SportsResponseCommand”,DelegateCommand对象将帮助您这样做
public class DelegateCommand : ICommand
{
private readonly Action<object> _ExecuteMethod;
private readonly Func< object, bool> _CanExecuteMethod;
#region Constructors
public DelegateCommand(Action<object>executeMethod, Func<object, bool> canExecuteMethod)
{
if (null == executeMethod)
{
throw new ArgumentNullException("executeMethod", "Delegate Command Delegates Cannot Be Null");
}
_ExecuteMethod = executeMethod;
_CanExecuteMethod = canExecuteMethod;
}
public DelegateCommand(Action<object>executeMethod) : this(executeMethod, null) { }
#endregion
#region Methods
public bool CanExecute(object parameter)
{
if (_CanExecuteMethod == null) return true;
return _CanExecuteMethod(parameter);
}
public void Execute(object parameter)
{
if (_ExecuteMethod == null) return;
_ExecuteMethod(parameter);
}
bool ICommand.CanExecute(object parameter)
{
return CanExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
void ICommand.Execute(object parameter)
{
Execute(parameter);
}
#endregion
}
然后在XAML中
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" >
<CheckBox DataContext="{Binding Path=Sports[Football]}"
IsChecked="{Binding IsChecked, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}"
CommandParameter="Football"
Content="Football"
Margin="5" />
<CheckBox DataContext="{Binding Path=Sports[Hockey]}"
IsChecked="{Binding IsChecked, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}"
CommandParameter="Hockey"
Content="Hockey"
Margin="5" />
<CheckBox DataContext="{Binding Path=Sports[Golf]}" IsChecked="{Binding IsChecked, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}"
CommandParameter="Golf"
Content="Golf"
Margin="5" />
</StackPanel>
我强烈建议您阅读此
我在下面描述了一个解决方案,我试图不修改您的XAML代码,但这不是唯一的方法(或最佳方法),而是包含所有必要的元素
第一步你们需要你们的模型,我称之为模型运动
public class Model_Sport : INotifyPropertyChanged
{
#region Constructor
public Model_Sport(string name, ICommand command)
{
Name = name;
SportsResponseCommand = command;
}
#endregion
static readonly PropertyChangedEventArgs _NameEventArgs = new PropertyChangedEventArgs("Name");
private string _Name = null;
public string Name
{
get { return _Name; }
set
{
_Name = value;
OnPropertyChanged(_NameEventArgs);
}
}
static readonly PropertyChangedEventArgs _SportsResponseCommandEventArgs = new PropertyChangedEventArgs("SportsResponseCommand");
private ICommand _SportsResponseCommand = null;
public ICommand SportsResponseCommand
{
get { return _SportsResponseCommand; }
set
{
_SportsResponseCommand = value;
OnPropertyChanged(_SportsResponseCommandEventArgs);
}
}
static readonly PropertyChangedEventArgs _IsCheckedEventArgs = new PropertyChangedEventArgs("IsChecked");
private bool _IsChecked = false;
public bool IsChecked
{
get { return _IsChecked; }
set
{
_IsChecked = value;
OnPropertyChanged(_IsCheckedEventArgs);
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
{
if (PropertyChanged != null)
{
PropertyChanged(this, eventArgs);
}
}
#endregion
}
现在您需要一种方法来委托您的命令“SportsResponseCommand”,DelegateCommand对象将帮助您这样做
public class DelegateCommand : ICommand
{
private readonly Action<object> _ExecuteMethod;
private readonly Func< object, bool> _CanExecuteMethod;
#region Constructors
public DelegateCommand(Action<object>executeMethod, Func<object, bool> canExecuteMethod)
{
if (null == executeMethod)
{
throw new ArgumentNullException("executeMethod", "Delegate Command Delegates Cannot Be Null");
}
_ExecuteMethod = executeMethod;
_CanExecuteMethod = canExecuteMethod;
}
public DelegateCommand(Action<object>executeMethod) : this(executeMethod, null) { }
#endregion
#region Methods
public bool CanExecute(object parameter)
{
if (_CanExecuteMethod == null) return true;
return _CanExecuteMethod(parameter);
}
public void Execute(object parameter)
{
if (_ExecuteMethod == null) return;
_ExecuteMethod(parameter);
}
bool ICommand.CanExecute(object parameter)
{
return CanExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
void ICommand.Execute(object parameter)
{
Execute(parameter);
}
#endregion
}
然后在XAML中
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" >
<CheckBox DataContext="{Binding Path=Sports[Football]}"
IsChecked="{Binding IsChecked, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}"
CommandParameter="Football"
Content="Football"
Margin="5" />
<CheckBox DataContext="{Binding Path=Sports[Hockey]}"
IsChecked="{Binding IsChecked, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}"
CommandParameter="Hockey"
Content="Hockey"
Margin="5" />
<CheckBox DataContext="{Binding Path=Sports[Golf]}" IsChecked="{Binding IsChecked, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}"
CommandParameter="Golf"
Content="Golf"
Margin="5" />
</StackPanel>
Beat me to it,但是您应该从复选框XAMLBeat me to it中删除Command/CommandParameter,但是您应该从复选框XAMLIs中删除Command/CommandParameter,使用复选框列表是您的一个选项吗?使用复选框列表是您的一个选项吗?感谢您Fred Jand的详细实施。我已经读到,如果不在模型中实现INotifyPropertyChanged,这将是一件好事。你同意这种说法吗?您对使用RelayCommand而不是DelegateCommand有什么看法?您看到任何缺点了吗?实际上RelayCommand和DelgateCommad几乎是相同的实体RelayCommand是Microsoft复合应用程序库中DelegateCommand的简化变体。如果你想要更真实的delegatecommand实现,我在这里放的实际上是一个RelayCommand。请注意,它们只是名称,并且在这几年中开发了这两个命令的不同变体!关键是他们有完全相同的概念。您可以创建自己版本的delegatecommand或relaycommand!正如我在本例中所做的:)关于“INotifyPropertyChanged”,它取决于应用程序!如果模型表示独立更改的内容,并且对应用程序的其他部分(viewmodel除外)有副作用,则最好在模型中更改InotifyProperty。但如果