我如何处理多个复选框在MVVM模式

本文关键字:复选框 MVVM 模式 何处理 处理 | 更新日期: 2023-09-27 18:09:57

WPF中的绑定复选框是常见的问题,但我仍然没有找到初学者容易遵循的示例代码。我在WPF中有一个复选框列表来选择最喜欢的运动名称。在我的例子中,复选框的数量是静态的。谁能告诉我如何实现这个问题的ViewModel ?

FavoriteSportsView.xaml:

  <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>

FavoriteSportsViewModel.cs

  public class FavoriteSportsViewModel.cs {
    //Since I am using the same IsChecked in all check box options, I found all check 
    //boxes gets either checked or unchecked when I just check or uncheck one option.
    //How do i resolve this issue? I don't think i need seprate IsChecked for each 
    //check box option.
    private bool _isChecked;
    public bool IsChecked{
      get {
           return _isChecked;
       }
      set { if (value != _isChecked) 
             _isChecked = value;
            this.OnPropertyChanged("IsChecked");
       }
    }

    //How do i detect parameter in this method?
    private ICommand _sportsResponseCommand;
    public ICommand SportsResponseCommand
    {
        get
        {
            if (_sportsResponseCommand== null)
                _sportsResponseCommand= new
                    RelayCommand(a => DoCollectSelectedGames(), p => true);
            return _sportsResponseCommand;
        }
        set
        {
            _sportsResponseCommand= value;
        }
    }
    private void DoCollectSelectedGames(){ 
      //Here i push all selected games in an array
    }

    public abstract class ViewModelBase : INotifyPropertyChanged
    {
       public event PropertyChangedEventHandler PropertyChanged;
       public void OnPropertyChanged(string propertyName)
       {
         if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
       }
    }
  }

我不确定如何在以上ViewModel中做以下操作:1. 我如何实现一个方法来处理我所有的选项?2. 如何检测每个复选框以查看是否选中3.我如何利用CommandParameter?4. 如何正确实现SportsResponseCommand

我如何处理多个复选框在MVVM模式

您的视图模型应该看起来像这样:

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属性将视图模型与视图关联(这很可能在后面的WindowUserControl代码中,尽管有很多方法可以实现这一点)。

最后,更新你的绑定,使它们看起来像:

<CheckBox IsChecked="{Binding Football, Mode=TwoWay}"  
 Content="Football" 
 Margin="5" />
<CheckBox IsChecked="{Binding Golf, Mode=TwoWay}"   
 Content="Football" 
 Margin="5" />

作为最后的注释,您不应该真的需要绑定Command属性—您可以编写任何您需要在视图模型的属性设置器中运行的代码。

我强烈建议你阅读这篇文章http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
我在下面描述了一个解决方案,我试图不修改你的XAML代码,但这不是唯一的方法(或最好的方法),但包含了所有必要的元素!

首先你需要你的模型我把它命名为Model_Sport

    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
    }

现在你需要一种方法来委托你的命令"sportsresponseccommand",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
    }

现在是" ViewModel "

    public class ViewModel
    {
        #region property
        public Dictionary<string, Model_Sport> Sports { get; set; }
        public DelegateCommand SportsResponseCommand { get; set; }
        #endregion
        public ViewModel()
        {
            Sports = new Dictionary<string, Model_Sport>();
            SportsResponseCommand = new DelegateCommand(p => execute_SportsResponseCommand(p));
            buildSports();
        }
        private void buildSports()
        {
            Model_Sport football = new Model_Sport("Football", SportsResponseCommand);
            Model_Sport golf = new Model_Sport("Golf", SportsResponseCommand);
            Model_Sport hockey = new Model_Sport("Hockey", SportsResponseCommand);
            football.IsChecked = true; // just for test
            Sports.Add(football.Name, football);
            Sports.Add(golf.Name, golf);
            Sports.Add(hockey.Name, hockey);
        }
        private void execute_SportsResponseCommand(object p)
        {
            // TODO :what ever you want
            MessageBox.Show(p.ToString());
        }
    }

现在视图记得为你的窗口设置数据上下文公共主窗口(){

        InitializeComponent();
        this.DataContext = new ViewModel();

    }

在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>

如果你只是想要一个属性在你的ViewModel得到更新时,IsChecked的变化,替换IsChecked绑定到一个布尔属性在你的ViewModel引发NotifyPropertyChanged的"集"

现在,如果你想在每次IsChecked更改时对3个复选框中的一个执行操作:

首先,将CommandParameter替换为"{Binding RelativeSource={RelativeSource Mode=Self}}"

在你的ViewModel(应该实现INotifyPropertyChanged)中,创建一个iccommand (SportsResponseCommand),它接受一个CheckBox In参数。

在命令的方法中,检查复选框的内容,并检查"IsChecked"属性,然后对它们进行处理。

您可以通过使用

来分配视图模型
 //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中实现绑定

<CheckBox IsChecked="{Binding Football, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}" CommandParameter="Football" Content="Football" Margin="5" />

<CheckBox IsChecked="{Binding Golf, Mode=TwoWay}"
Command="{Binding Path=SportsResponseCommand}" CommandParameter="Football" Content="Football" Margin="5" />