选择datagrid标题中的所有复选框及其在wpf mvvm中的绑定

问题描述 投票:0回答:4

我正在研究wpf(mvvm架构)。我正在使用数据网格列出复选框,并在标题中单击“全选”复选框,我希望选中所有复选框,反之亦然。请帮忙。

我在这里给出我的代码描述...... 这是View.xaml

<DataGridCheckBoxColumn Binding="{Binding IsSelected}" Width="50" >
    <DataGridCheckBoxColumn.HeaderTemplate>
        <DataTemplate x:Name="dtAllChkBx">
            <CheckBox Name="cbxAll" Content="All" IsChecked="{Binding Path=DataContext.AllSelected,RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
        </DataTemplate>
    </DataGridCheckBoxColumn.HeaderTemplate>
</DataGridCheckBoxColumn>
<DataGridTemplateColumn Header="Name" Width="SizeToCells" IsReadOnly="True">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding UsecaseName}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>             

下面是viewmodel类

private bool _IsSelected;
public bool IsSelected
{
    get { return _IsSelected; }
    set
    {
        _IsSelected = value;
        OnPropertyChanged("IsSelected");
    }
}

private bool _AllSelected;
public bool AllSelected
{
    get { return _AllSelected; }
    set
    {
        _AllSelected = value;
        foreach (var reportListItemModel in UsecaseListItems)
        {
            reportListItemModel.IsSelected = this._AllSelected;
        }
        OnPropertyChanged("IsSelected");

    }
}   

private ObservableCollection<UseCase> _usecaseListItems = new ObservableCollection<UseCase>();
public ObservableCollection<UseCase> UsecaseListItems
{
    get { return _usecaseListItems; }
    set {
        _usecaseListItems = value;
        OnPropertyChanged("UsecaseListItems");
    }
}

公共类用例:BaseNotifyPropertyChanged { 公共字符串 UsecaseName { get;放; }

    public bool IsSelected { get; set; }

}

还应该做什么才能使全选复选框正常工作?

c# wpf checkbox mvvm wpfdatagrid
4个回答
3
投票

您的 UseCase 类必须实现 INotifyPropertyChanged 接口

public class UseCase : INotifyPropertyChanged
{
    //...
    private bool _isSelected;
    public bool IsSelected
    {
        get
        {
            return _isSelected;
        }
        set
        {
            _isSelected = value;
            NotifyPropertyChanged("IsSelected");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

编辑:这里我得到了一个运行良好的完整示例

*.xaml(视图)

<DataGrid x:Name="dataGrid" ItemsSource="{Binding MyCollection}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridCheckBoxColumn Binding="{Binding IsSelected}" Width="50" >
            <DataGridCheckBoxColumn.HeaderTemplate>
                <DataTemplate x:Name="dtAllChkBx">
                    <CheckBox Name="cbxAll" DataContext="{Binding ElementName=dataGrid, Path=DataContext}" Command="{Binding MyCommand}" CommandParameter="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}"/>
                </DataTemplate>
            </DataGridCheckBoxColumn.HeaderTemplate>
        </DataGridCheckBoxColumn>
        <DataGridTemplateColumn Header="Name" Width="SizeToCells" IsReadOnly="True">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding UsecaseName}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

*.cs(视图模型)

public class MainViewModel : INotifyPropertyChanged
{
    public MainViewModel()
    {
        for (int i = 0; i < 100; i++)
        {
            MyCollection.Add(new UseCase { UsecaseName = "name " + i, IsSelected = false });
        }
        MyCommand = new RelayCommand(MyCommandAction);
    }


    private ObservableCollection<UseCase> myCollection = new ObservableCollection<UseCase>();

    public ObservableCollection<UseCase> MyCollection
    {
        get
        {
            return myCollection;
        }
        set
        {
            myCollection = value;
            NotifyPropertyChanged("MyCollection");
        }
    }

    public RelayCommand MyCommand { get; set; }
    private  void MyCommandAction(object obj)
    {
        foreach (var item in MyCollection)
        {
            item.IsSelected = (bool)obj;
        }
    }



    //NotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

*.cs(模型)

public class UseCase : INotifyPropertyChanged
{
    public string UsecaseName { get; set; }
    private bool _isSelected;
    public bool IsSelected
    {
        get
        {
            return _isSelected;
        }
        set
        {
            _isSelected = value;
            NotifyPropertyChanged("IsSelected");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

2
投票

虽然存在很多解决方案,但我想找到一个我经常遇到的特定问题陈述,类似于: 在 WPF DataGrid 中,通过 MVVM 方法绑定,

  1. 如果我选中标题中的“全选”复选框,则应选中该列中的所有复选框。
  2. 如果我取消选中标题中的“全选”复选框,则应取消选中该列中的所有复选框
  3. 如果我取消选中任何行的该列中的任何复选框,则应取消选中标题中的“全选”复选框。
  4. 如果该列中的所有复选框均已选中(每行一个),则应选中标题中的“全选”复选框(留给您探索;))

型号:

public class Employee : INotifyPropertyChanged
{
        private int _id;
        private string _name;
        private double _salary;
        private bool _isSelected;

        public int Id { get => _id; set => _id = value; }
        public string Name { get => _name; set => _name = value; }
        public double Salary { get => _salary; set => _salary = value; }
        public bool IsSelected
        {
            get
            {
                return _isSelected;
            }
            set
            {
                _isSelected = value;
                OnPropertyChanged(nameof(IsSelected));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
            }
        }
}

视图模型:

public class EmployeeDetailsViewModel
{
        public EmployeeDetailsViewModel()
        {
            SelectAllCommand = new DelegateCommand<bool?>(HandleSelectAllCommand);
        }

        ObservableCollection<Employee> _employees = null;
        /// <summary>
        /// Collection bound to DataGrid
        /// </summary>
        public ObservableCollection<Employee> Employees { get => _employees; set { _employees = value; } }

        /// <summary>
        /// Command bound to SelectAll checkbox in XAML
        /// </summary>
        public ICommand SelectAllCommand { get; set; }

        private void HandleSelectAllCommand(bool? isChecked)
        {
            if (isChecked.HasValue)
            {
                foreach (var employee in Employees)
                {
                    employee.IsSelected = isChecked.Value;
                }
            }
        }

        void PrepareData()
        {
            this.Employees = new ObservableCollection<Employee>()
            {
                new Employee{Id=1, Name="abc", Salary=100000.00d},
                new Employee{Id=2, Name="def", Salary=200000.00d},
                new Employee{Id=3, Name="ghi", Salary=300000.00d},
                new Employee{Id=4, Name="jkl", Salary=400000.00d}
            };
        }
}

视图(XAML):

<DataGrid ItemsSource="{Binding Employees}" AutoGenerateColumns="False" CanUserAddRows="False" >
        <DataGrid.Columns>
            <DataGridTemplateColumn >
                <DataGridTemplateColumn.Header>
                    <CheckBox x:Name="chkSelectAll">
                        <i:Interaction.Triggers>
                            <i:EventTrigger  EventName="Click">
                                <i:InvokeCommandAction Command="{Binding Path = DataContext.SelectAllCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid,AncestorLevel=1}}" 
                                                       CommandParameter="{Binding ElementName=chkSelectAll, Path=IsChecked, UpdateSourceTrigger=PropertyChanged}"/>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </CheckBox>
                </DataGridTemplateColumn.Header>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
                            <i:Interaction.Triggers>
                                <i:EventTrigger  EventName="Unchecked">
                                    <local:EventTriggerPropertySetAction TargetObject="{Binding ElementName=chkSelectAll}" PropertyName="IsChecked" PropertyValue="False"/>
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </CheckBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>

            </DataGridTemplateColumn>
            <DataGridTextColumn Binding="{Binding Id}" Header="Id"/>
            <DataGridTextColumn Binding="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Header="Name"/>
            <DataGridTextColumn Binding="{Binding Salary, UpdateSourceTrigger=PropertyChanged}" Header="Salary"/>
        </DataGrid.Columns>
</DataGrid>

要访问交互触发器,您需要将以下名称空间添加到 Window/UserControl 标记中:

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
....
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">

简化的重要部分是由于

<local:SetPropertyAction ...
基于这个SO答案这个SO答案

当您访问这些链接时,不要忘记投票和鼓励;)

希望这对某人有所帮助!


0
投票

您可以使用 RegisteredAttachedProperty 使其成为可能。 在这里,您可以找到样本。你可以从那里得到启发。


0
投票

您可能需要这个解决方案:
https://stackoverflow.com/a/77603913/6859121
易于使用!

<DataGrid.Columns>
    <!-- Binding to bool property for entity which means it checked -->
    <fc:DataGridCheckAllColumn Binding="{Binding IsChecked}" />
    <!-- else columns -->
    <DataGridTextColumn Binding="{Binding EntityName}" />
</DataGrid.Columns>
© www.soinside.com 2019 - 2024. All rights reserved.