根据复选框列表选择MVVM启用WPF按钮

时间:2012-05-07 09:59:27

标签: c# wpf mvvm .net-4.0 prism

我有一个sports的复选框列表,它使用MVVM模式绑定到一个可观察的集合。 用户可以选择他喜欢的任意数量的运动,当按下确定按钮时,必须在消息框中显示所选的运动(为了问题简化了代码)。

只有在选择了一项或多项运动时,必须启用“确定”按钮,此时此功能不起作用。使用IsValid启用\禁用该按钮,是否有任何方法可以执行此操作每次检查其中一个复选框时的方法?

我无法使用<Button IsEnabled="{Binding ElementName=checkBox1, Path=IsChecked}" />,因为开发代码中有多个属性需要在使用按钮之前检查其有效性,因为我使用的是Prism,所以这个应该使用如果可能的话,IsValid方法

XAML

<Window x:Class="WpfApplication13.MVVM.ComboboxWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:prism="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"
        xmlns:local="WpfApplication13.MVVM" Title="MainWindow" Height="170" Width="507">
    <Grid>
        <ListBox ItemsSource="{Binding Sports}" Name="lbModules" ScrollViewer.VerticalScrollBarVisibility="Visible" 
                 Height="72" Margin="3" VerticalAlignment="Top">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <CheckBox Content="{Binding Text}" IsChecked="{Binding IsChecked,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Name="chkModules" Margin="0,5,0,0" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button Height="27" Width="70" Margin="3,80,3,3" VerticalAlignment="Top" 
                Content="OK" HorizontalAlignment="Left" 
                prism:Click.Command="{Binding Path=NewCommand}"></Button>
    </Grid>
</Window>

查看模型

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using Microsoft.Practices.Composite.Presentation.Commands;

namespace WpfApplication13.MVVM
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public DelegateCommand<object> NewCommand { get; protected set; }
        public event PropertyChangedEventHandler PropertyChanged;

        private ObservableCollection<ListHelper> modules = new ObservableCollection<ListHelper>();
        public ObservableCollection<ListHelper> Sports
        {
            get { return modules; }
            set { modules = value; OnPropertyChanged("Sports"); }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                NewCommand.RaiseCanExecuteChanged();
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public MainWindowViewModel()
        {
            ListHelper item1 = new ListHelper() { Text = "Footbal", IsChecked = false };
            ListHelper item2 = new ListHelper() { Text = "Boxing", IsChecked = false };
            ListHelper item3 = new ListHelper() { Text = "Basketball", IsChecked = false };

            Sports.Add(item1);
            Sports.Add(item2);
            Sports.Add(item3);

            NewCommand = new DelegateCommand<object>(NewTemplate, IsValid);
        }

        private bool IsValid(object parameter)
        {
            //TODO:This method must execute EVERYTIME any of the checkboxes are checked\unchecked.(currently not happening)
            //The return value then determines the enabled state of the button.
            return Sports.Any(e => e.IsChecked);
        }

        private void NewTemplate(object parameter)
        {
            //Display a list of selected sports
            string sports = String.Empty;
            Sports.Where(e => e.IsChecked).ToList().ForEach(c => sports += c.Text + " ");
            MessageBox.Show(sports);
        }
    }

    public class ListHelper
    {
        public String Text { get; set; }

        private bool isChecked = false;
        public Boolean IsChecked 
        {
            get { return isChecked; }
            //The setter is executed everytime the checkbox is checked
            set {isChecked = value;}
        }
    }
}

4 个答案:

答案 0 :(得分:1)

当选中/取消选中复选框时,您必须发出NewCommand(由IsValid确定)的可用性变化信号。你必须这样称呼:

NewCommand.RaiseCanExecuteChanged();
每当ListHelper.IsChecked更新时

。你必须想出一个很好的方法来连接它。您有几个选项,但最直接的可能是ListHelper提供MainViewModel的引用,允许它在视图模型上调用适当的方法。

或者,如果您想避免创建强耦合,可以在INotifyPropertyChanged中实现ListHelper,并让MainViewModel侦听对IsChecked的更改。

答案 1 :(得分:0)

我认为您的问题的原因是,PRISM DelegateCommand不包括requery支持。此站点描述了此问题的正确解决方法 http://compositewpf.codeplex.com/discussions/44750?ProjectName=compositewpf

答案 2 :(得分:0)

必须更改ListHelper类,如下所示。按钮验证现在按预期执行:

 public class ListHelper : INotifyPropertyChanged
    {
        private DelegateCommand<object> _command = null;
        private string _propertyName = String.Empty;

        public ListHelper(DelegateCommand<object> command,string propertyName)
        {
            _command = command;
            propertyName = _propertyName;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public String Text { get; set; }

        private bool isChecked = false;
        public Boolean IsChecked 
        {
            get { return isChecked; }
            //The setter is executed everytime the checkbox is checked
            set 
            {
                isChecked = value;
                OnPropertyChanged(_propertyName);
            }
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null && _command != null)
            {
                _command.RaiseCanExecuteChanged();
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

答案 3 :(得分:0)

我有最好的解决方案:致电

rand(1, 1000000);

来自你的checkbok IsChecked setter的设定者:

CommandManager.InvalidateRequerySuggested();

无需强烈引用该命令。至少可以从.NET 4.0获得。