WPF选择DataGrid中的所有复选框 [英] WPF Select all CheckBox in a DataGrid

查看:98
本文介绍了WPF选择DataGrid中的所有复选框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图选择一个DataGrid中的所有CheckBox,但是使用下面的代码却没有得到任何结果



这是我正在调用的函数当单击主CheckBox时

  private void CheckUnCheckAll(对象发送者,RoutedEventArgs e)
{
CheckBox chkSelectAll =((复选框)发送器);
if(chkSelectAll.IsChecked == true)
{
dgUsers.Items.OfType< CheckBox>()。ToList()。ForEach(x => x.IsChecked = true);
}
else
{
dgUsers.Items.OfType< CheckBox>()。ToList()。ForEach(x => x.IsChecked = false);
}
}

dgUsers是DataGrid,但据我所知,任何复选框都是找到。



这是我使用的XAML或通过在datagrid中创建CheckBox

 < DataGrid.Columns> 
< DataGridCheckBoxColumn x:Name = col0 HeaderStyle = {StaticResource ColumnHeaderGripperStyle}>
< DataGridCheckBoxColumn.HeaderTemplate>
< DataTemplate>
< CheckBox Click = CheckUnCheckAll>
< / CheckBox>
< / DataTemplate>
< /DataGridCheckBoxColumn.HeaderTemplate>
< / DataGridCheckBoxColumn>
< DataGrid.Columns>

这是我的DataGrid的图片





是否可以通过编程方式选择所有复选框?



编辑
我已经尝试遵循



正确的操作位置在您的ViewModel。您的CheckBox可以具有三个状态,您想使用所有三个状态:


  1. 已检查-每个项目都已检查

  2. 未选中-未选中任何项目

  3. 不确定-一些项目已选中,某些未选中

您将希望在选中/取消选中某项时更新CheckBox,并在更改CheckBox时更新所有项目-仅执行此一种方法将使CheckBox处于无效状态,这可能会对它产生负面影响用户体验。我的建议:一路走好,并正确实施。为此,您需要知道引起更改的原因-条目的CheckBox或标题中的CheckBox。



这是我要怎么做:



首先,您需要为商品添加ViewModel,在这里使用了一个非常简化的示例,仅包含 IsChecked 属性。

 公共类条目:INotifyPropertyChanged 
{
私人布尔值_isChecked;

public bool IsChecked
{
get => _isChecked;
set
{
if(value == _isChecked)return;
_isChecked =值;
OnPropertyChanged();
}
}

公共事件PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]
受保护的虚拟无效OnPropertyChanged([CallerMemberName]字符串propertyName = null)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName)) ;
}
}

您的主ViewModel将具有所有项的集合。每当项目的 IsChecked 属性更改时,您都必须检查所有项目是否已选中/未选中,并更新标题中的CheckBox(或更确切地说,

  public class ViewModel:INotifyPropertyChanged 
{
public List< Entry>条目
{
get => _entries;
set
{
if(Equals(value,_entries))return;
_entries =值;
OnPropertyChanged();
}
}

public ViewModel()
{
//只是一些演示数据
Entries = new List< Entry>
{
个新Entry(),
个新Entry(),
个新Entry(),
个新Entry()
};

//确保聆听更改。
//如果添加/删除项目,也不要原谅添加/删除事件处理程序
foreach(条目中的条目)
{
entry.PropertyChanged + = EntryOnPropertyChanged;
}
}

private void EntryOnPropertyChanged(object sender,PropertyChangedEventArgs args)
{
//仅重新检查IsChecked属性是否已更改
if(args.PropertyName == nameof(Entry.IsChecked))
RecheckAllSelected();
}

private void AllSelectedChanged()
{
//此更改是否由其他更改引起?
//返回,因此如果(_allSelectedChanging)返回,我们不会弄乱
的事情;

试试
{
_allSelectedChanging = true;

//如果(AllSelected == true)
{
foreach(Entry kommune in Entries)
kommune。
kommune.IsChecked当然可以简化
= true;
}
else if(AllSelected == false)
{
foreach(Entry kommune in Entries)
kommune.IsChecked = false;
}
}
最后
{
_allSelectedChanging = false;
}
}

private void RecheckAllSelected()
{
//此更改是否由其他更改引起?
//返回,因此如果(_allSelectedChanging)返回,我们不会弄乱
的事情;

试试
{
_allSelectedChanging = true;

if(Entries.All(e => e.IsChecked))
AllSelected = true;
else if(Entries.All(e =>!e.IsChecked))
AllSelected = false;
else
AllSelected = null;
}
最终
{
_allSelectedChanging = false;
}
}

公共布尔? AllSelected
{
get => _allSelected;
set
{
if(value == _allSelected)return;
_allSelected =值;

//设置所有其他复选框
AllSelectedChanged();
OnPropertyChanged();
}
}

私人布尔值_allSelectedChanging;
私人列表<条目> _entries;
私人布尔? _allSelected;
公共事件PropertyChangedEventHandler PropertyChanged;

[NotifyPropertyChangedInvocator]
受保护的虚拟无效OnPropertyChanged([CallerMemberName]字符串propertyName = null)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName)) ;
}
}

Demo XAML:

 < DataGrid ItemsSource = {绑定条目} AutoGenerateColumns = False IsReadOnly = False CanUserAddRows = False> ; 
< DataGrid.Columns>
< DataGridCheckBoxColumn Binding = {Binding IsChecked,UpdateSourceTrigger = PropertyChanged}>
< DataGridCheckBoxColumn.HeaderTemplate>
< DataTemplate>
< CheckBox IsChecked = {Binding RelativeSource = {RelativeSource Mode = FindAncestor,AncestorType = local:MainWindow},Path = ViewModel.AllSelected}>全选< / CheckBox>
< / DataTemplate>
< /DataGridCheckBoxColumn.HeaderTemplate>
< / DataGridCheckBoxColumn>
< /DataGrid.Columns>
< / DataGrid>


I'm trying to select all CheckBox in a DataGrid but I didn't get any result using this code bellow

This is the function that I'm calling when the main CheckBox is clicked

private void CheckUnCheckAll(object sender, RoutedEventArgs e)
{
    CheckBox chkSelectAll = ((CheckBox)sender);
    if (chkSelectAll.IsChecked == true)
    {
        dgUsers.Items.OfType<CheckBox>().ToList().ForEach(x => x.IsChecked = true);
    }
    else
    {
        dgUsers.Items.OfType<CheckBox>().ToList().ForEach(x => x.IsChecked = false);
    }
}

dgUsers is the DataGrid but as I realize any checkbox is found.

This is the XAML that I'm using tho create the CheckBox in the datagrid

<DataGrid.Columns>
    <DataGridCheckBoxColumn x:Name="col0" HeaderStyle="{StaticResource ColumnHeaderGripperStyle}">
         <DataGridCheckBoxColumn.HeaderTemplate>
              <DataTemplate>
                   <CheckBox Click="CheckUnCheckAll" >
                   </CheckBox>
              </DataTemplate>
         </DataGridCheckBoxColumn.HeaderTemplate>
    </DataGridCheckBoxColumn>
<DataGrid.Columns>

And this is the picture of my DataGrid

Is there some way to select all checkbox programatically ?

Edit I already tried to follow this steps

that you can see that my code is the same there but didn't work to me

解决方案

TLDR; This is what you want, code below:

The proper place to do this would be in your ViewModel. Your CheckBox can have three states, all of which you want to make use of:

  1. Checked - Every item is checked
  2. Unchecked - No item is checked
  3. Indeterminate - Some items are checked, some are not

You will want to update the CheckBox whenever an item is checked/unchecked and update all items whenever the CheckBox was changed - implementing this only one way will leave the CheckBox in an invalid state which might have a negative impact on user experience. My suggestion: go all the way and implement it properly. To do this you need to be aware of which caused the change - the CheckBox of an entry or the CheckBox in the header.

Here is how I would do it:

First you need a ViewModel for your items, I've used a very simplified one here that only contains the IsChecked property.

public class Entry : INotifyPropertyChanged
{
    private bool _isChecked;

    public bool IsChecked
    {
        get => _isChecked;
        set
        {
            if (value == _isChecked) return;
            _isChecked = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Your main ViewModel will have a collection of all items. Whenever an item's IsChecked property changes, you'll have to check if all items are checked/unchecked and update the CheckBox in the header (or rather the value of its datasource).

public class ViewModel : INotifyPropertyChanged
{
    public List<Entry> Entries
    {
        get => _entries;
        set
        {
            if (Equals(value, _entries)) return;
            _entries = value;
            OnPropertyChanged();
        }
    }

    public ViewModel()
    {
        // Just some demo data
        Entries = new List<Entry>
        {
            new Entry(),
            new Entry(),
            new Entry(),
            new Entry()
        };

        // Make sure to listen to changes. 
        // If you add/remove items, don't forgat to add/remove the event handlers too
        foreach (Entry entry in Entries)
        {
            entry.PropertyChanged += EntryOnPropertyChanged;
        }
    }

    private void EntryOnPropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        // Only re-check if the IsChecked property changed
        if(args.PropertyName == nameof(Entry.IsChecked))
            RecheckAllSelected();
    }

    private void AllSelectedChanged()
    {
        // Has this change been caused by some other change?
        // return so we don't mess things up
        if (_allSelectedChanging) return;

        try
        {
            _allSelectedChanging = true;

            // this can of course be simplified
            if (AllSelected == true)
            {
                foreach (Entry kommune in Entries)
                    kommune.IsChecked = true;
            }
            else if (AllSelected == false)
            {
                foreach (Entry kommune in Entries)
                    kommune.IsChecked = false;
            }
        }
        finally
        {
            _allSelectedChanging = false;
        }
    }

    private void RecheckAllSelected()
    {
        // Has this change been caused by some other change?
        // return so we don't mess things up
        if (_allSelectedChanging) return;

        try
        {
            _allSelectedChanging = true;

            if (Entries.All(e => e.IsChecked))
                AllSelected = true;
            else if (Entries.All(e => !e.IsChecked))
                AllSelected = false;
            else
                AllSelected = null;
        }
        finally
        {
            _allSelectedChanging = false;
        }
    }

    public bool? AllSelected
    {
        get => _allSelected;
        set
        {
            if (value == _allSelected) return;
            _allSelected = value;

            // Set all other CheckBoxes
            AllSelectedChanged();
            OnPropertyChanged();
        }
    }

    private bool _allSelectedChanging;
    private List<Entry> _entries;
    private bool? _allSelected;
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Demo XAML:

<DataGrid ItemsSource="{Binding Entries}" AutoGenerateColumns="False" IsReadOnly="False" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridCheckBoxColumn Binding="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}">
            <DataGridCheckBoxColumn.HeaderTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:MainWindow}, Path=ViewModel.AllSelected}">Select All</CheckBox>
                </DataTemplate>
            </DataGridCheckBoxColumn.HeaderTemplate>
        </DataGridCheckBoxColumn>
    </DataGrid.Columns>
</DataGrid>

这篇关于WPF选择DataGrid中的所有复选框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆