【问题标题】:WPF - MVVM : How to Check/Uncheck all Items in a ListViewWPF - MVVM:如何检查/取消选中 ListView 中的所有项目
【发布时间】:2023-03-24 20:12:01
【问题描述】:

我有以下要求:

  1. 窗口将显示带有多个项目的ListView
  2. 用户应该能够选中(复选框)任何项目。 a) 如果是一项,则应取消选中并禁用所有项。 b) 如果选中的项目未选中,则应启用所有项目。

截至目前,我有以下不完整的代码。

主窗口 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 的数据模板:

<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));
        }
    }
}

【问题讨论】:

  • 您的列表中是否有任何ItemsSource?在这种情况下,您应该能够在将项目添加到源时侦听 CheckBox changed 事件,然后在那里更改您的属性。如果您需要任何示例代码,请告诉我
  • "用户应该能够选中(复选框)任何项目。a)如果是一项,则所有项目都应取消选中并禁用。b)如果选中的项目未选中,则应启用所有项目。 "我认为您在描述 RadioButton。
  • @Jim 几乎 - 不同之处在于,如果选中其中一个复选框,则其他复选框应禁用,因此您必须主动取消选中该复选框才能选择另一个复选框。原因,我不知道 - 我也会选择单选按钮
  • @Jim Default 是正确的,它是客户的要求。

标签: c# wpf listview mvvm


【解决方案1】:

这是一个有趣的问题。由于您想要的操作适用于列表中的所有项目,因此此逻辑应处于列表类级别。您的 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 的逻辑放在列表视图模型中,这样看起来更清晰,更容易编写测试代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 1970-01-01
    • 2018-02-15
    • 1970-01-01
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多