c# - WPF 选择 DataGrid 中的所有 CheckBox

标签 c# wpf xaml datagrid

我正在尝试选择 DataGrid 中的所有复选框,但使用下面的代码我没有得到任何结果

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

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 是 DataGrid,但我意识到找到了任何复选框。

这是我用来在数据网格中创建 CheckBox 的 XAML

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

这是我的DataGrid的图片

enter image description here

有没有办法以编程方式选择所有复选框?

编辑 我已经尝试关注 this steps

你可以看到我的代码在那里是一样的,但对我不起作用

最佳答案

TLDR;这就是你想要的,代码如下:

Demo of what I'm about to explain

执行此操作的正确位置是在您的 ViewModel 中。您的 CheckBox 可以具有三种状态,所有这些您都想使用:

  1. 已检查 - 每一项都已检查
  2. 未选中 - 没有项目被选中
  3. 不确定 - 有些项目已检查,有些未检查

您将希望在选中/取消选中某个项目时更新 CheckBox,并在 CheckBox 更改时更新所有项目 - 仅以这种方式实现将使 CheckBox 处于无效状态,这可能会对用户体验产生负面影响。我的建议:一路走好,落实好。为此,您需要了解导致更改的原因 - 条目的 CheckBox 或标题中的 CheckBox。

下面是我的做法:

首先您需要为您的项目创建一个 ViewModel,我在这里使用了一个非常简化的模型,它只包含 IsChecked 属性。

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

您的主 ViewModel 将包含所有项目的集合。每当项目的 IsChecked 属性发生变化时,您都必须检查是否选中/未选中所有 项目并更新 header 中的 CheckBox(或者更确切地说是其数据源的值) .

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

演示 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>

关于c# - WPF 选择 DataGrid 中的所有 CheckBox,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48955781/

相关文章:

c# - 生产者-消费者同步问题

c# - 将布局保存到位图(Xamarin)

c# - 如何在 WPF 应用程序中结合使用 MVVM 和依赖注入(inject)?

wpf - 验证触发太早

c# - XAML Treeview,如何水平而不是垂直显示节点

c# - 如何使用 C# 创建带有日期时间的文本文件名

c# - 为什么我看不到对象的详细信息(ID、名称等)。我正在使用 mvc 4、razor、 Entity Framework

c# - 指定默认的空 DataTemplate 而不是默认的 'ToString()' DataTemplate

c# - 未找到数据绑定(bind)属性,为什么?

c# - 如何仅在TreeView中设置顶级项目的样式?