WPF - MVVM:如何检查/取消选中ListView中的所有项目

时间:2013-07-31 15:26:25

标签: c# wpf listview mvvm

我有以下要求:

  1. 窗口会显示包含多个项目的ListView
  2. 用户应该可以检查(复选框)任何项目。 a)如果有一个项目,则应取消选中并禁用所有项目。 b)如果未选中选中的项目,则应启用所有项目。
  3. 截至目前,我有以下不完整的代码。

    MainWindow XAML:

    <Window x:Class="WpfApplication4.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="520.149" Width="732.463">
        <Window.Resources>
            <ResourceDictionary Source="MainWindowResource.xaml" />
        </Window.Resources>
    
        <Grid>
         <ListView x:Name="myListBox" ItemTemplate="{StaticResource OfferingTemplate}">
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <UniformGrid Columns="3" VerticalAlignment="Top"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
            </ListView>
        </Grid>
    </Window>
    

    ListView的DataTemplete:

    <DataTemplate x:Key="OfferingTemplate">
        <StackPanel>
            <Grid IsEnabled="{Binding IsEnabled}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="8"></ColumnDefinition>
                    <ColumnDefinition Width="120"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="40"></RowDefinition>
                    <RowDefinition Height="50"></RowDefinition>
                    <RowDefinition Height="30"></RowDefinition>
                </Grid.RowDefinitions>
                <Rectangle Grid.Column="0" Grid.RowSpan="3" Fill="#F4CA16" />
                <Label
                    Grid.Column="1"
                    Grid.Row="0"
                    Content="{Binding Title}"
                    FontSize="18" FontWeight="Bold"
                    Margin="0,0,0,0" />
                <TextBlock
                    Grid.Column="1"
                    Grid.Row="1"
                    FontSize="10"
                    Text="{Binding Description}"
                    Foreground="Black"
                    TextWrapping="WrapWithOverflow"
                    Margin="5,0,0,0" />
                <CheckBox
                    Grid.Column="1"
                    Grid.Row="2"
                    FontSize="14"
                    IsChecked="{Binding IsSelected}"
                    VerticalAlignment="Bottom"
                    Margin="5,0,0,0">
    
                    <TextBlock Text="Select" Margin="0,-2,0,0"/>
                </CheckBox>
            </Grid>
        </StackPanel>
    </DataTemplate>
    

    型号:

    class MyModel
    {
        public string Title { get; set; }
        public string Description { get; set; }
        public bool IsSelected { get; set; }
        public bool IsEnabled { get; set; }
    }
    

    视图模型:

    class MyViewModel : INotifyPropertyChanged
    {
        private MyModel offering;
    
        public MyViewModel()
        {
            offering = new MyModel();
        }
    
        public int ID { get; set; }
        public string Title
        {
            get { return offering.Title; }
            set
            {
                offering.Title = value;
                RaisePropertyChanged("Title");
            }
        }
        public string Description
        {
            get { return offering.Description; }
            set
            {
                offering.Description = value;
                RaisePropertyChanged("Description");
            }
        }
        public bool IsSelected
        {
            get { return offering.IsSelected; }
            set
            {
                offering.IsSelected = value;
                RaisePropertyChanged("IsSelected");
            }
        }
        public bool IsEnabled
        {
            get { return offering.IsEnabled; }
            set
            {
                offering.IsEnabled = value;
                RaisePropertyChanged("IsEnabled");
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

1 个答案:

答案 0 :(得分:4)

这是一个有趣的问题。由于您想要的操作适用于列表中的所有项目,因此该逻辑应该在列表类级别中。你的MyViewModel类很好。你需要在列表类和XAML中添加一些逻辑,但是由于Prism,它很容易。

列表类(未在帖子中显示)包含:

    public ObservableCollection<MyViewModel> MyItems { get; set; } //Binding to ItemsSource

    private ICommand _selectCommand;

    public ICommand SelectCommand
    {
        get { return _selectCommand ?? (_selectCommand = new DelegateCommand<MyViewModel>(DoSelect)); }
    }

    private void DoSelect(MyViewModel myViewModel)
    {
        foreach(var item in MyItems)
            if (item != myViewModel)
            {
                item.IsSelected = false;
                item.IsEnabled = false;
            }
    }

    private ICommand _unselectCommand;

    public ICommand UnselectCommand
    {
        get { return _unselectCommand ?? (_unselectCommand = new DelegateCommand<MyViewModel>(DoUnselect)); }
    }

    private void DoUnselect(MyViewModel myViewModel)
    {
        foreach (var item in MyItems)
            if (item != myViewModel)
            {
                item.IsEnabled = true;
            }
    }

有两个命令,一个用于选择,另一个用于取消选择。魔术在XAML上:

      <ListView ItemsSource="{Binding Path=MyItems}" x:Name="listView">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding Path=IsSelected}" IsEnabled="{Binding Path=IsEnabled}">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Checked">
                                <i:InvokeCommandAction Command="{Binding ElementName=listView, Path=DataContext.SelectCommand}"
                                                       CommandParameter="{Binding}"/>
                            </i:EventTrigger>
                            <i:EventTrigger EventName="Unchecked">
                                <i:InvokeCommandAction Command="{Binding ElementName=listView, Path=DataContext.UnselectCommand}"
                                                       CommandParameter="{Binding}"/>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </CheckBox>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

使用Prism的触发器,您可以将CheckBox的Checked和Unchecked事件映射到列表视图模型的命令,并将项目视图模型作为参数传递。

它工作正常,但有一件事令人讨厌,设置项目的IsSelected是独立的。检查CheckBox时,后面的项目通过DataBinding设置为true,但所有其他项目都通过父视图模型设置。如果您的帖子是您的全部要求,您可以删除IsChecked绑定并在列表视图模型中设置一个IsSelected的逻辑,这看起来更清晰,更容易编写测试代码。