首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >WPF选择DataGrid中的所有CheckBox

WPF选择DataGrid中的所有CheckBox
EN

Stack Overflow用户
提问于 2018-02-24 04:28:32
回答 3查看 13.4K关注 0票数 10

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

这是单击主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的照片

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

编辑我已经尝试关注this steps

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-02-26 21:52:33

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

执行此操作的适当位置应该在ViewModel中。您的CheckBox可以有三种状态,您希望使用所有这些状态:

选中项目-每个项目都是checked

  • Unchecked -没有项目是checked

  • Indeterminate -某些项目已选中,有些项目不是

您可能希望在选中/取消选中某个项目时更新CheckBox,并在更改CheckBox时更新所有项目-仅以一种方式实现此操作将使CheckBox处于无效状态,这可能会对用户体验产生负面影响。我的建议是:一路走下去,正确地实现它。要做到这一点,您需要知道是哪个引起了更改-条目的CheckBox还是头中的CheckBox。

下面是我会怎么做:

首先,您需要为您的项目提供一个ViewModel,我在这里使用了一个非常简单的只包含IsChecked属性的the。

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属性更改时,您必须检查是否选中/取消选中所有项,并更新标题中的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>
票数 26
EN

Stack Overflow用户

发布于 2018-02-26 21:28:10

您在示例中所做的是遍历数据项,而不是遍历控件(我假设您没有作为ItemsSource的控件)。

在您发布的链接中,YourClass是来自ViewModel的类,即网格行的数据对象。

这种方法只需对您的CommandParameter):进行最少的代码更改即可工作(但我更喜欢在ViewModel中使用类似于将 IsChecked 绑定到 CheckUncheckCommand的CheckUncheckCommand+绑定的方式来处理它

<DataGridCheckBoxColumn x:Name="col0" HeaderStyle="{StaticResource ColumnHeaderGripperStyle}" DisplayIndex="0">

private void CheckUnCheckAll(object sender, RoutedEventArgs e)
{
    var chkSelectAll = sender as CheckBox;
    var firstCol = dgUsers.Columns.OfType<DataGridCheckBoxColumn>().FirstOrDefault(c => c.DisplayIndex == 0);
    if (chkSelectAll == null || firstCol == null || dgUsers?.Items == null)
    {
        return;
    }
    foreach (var item in dgUsers.Items)
    {
        var chBx = firstCol.GetCellContent(item) as CheckBox;
        if (chBx == null)
        {
            continue;
        }
        chBx.IsChecked = chkSelectAll.IsChecked;
    }
}
票数 3
EN

Stack Overflow用户

发布于 2019-05-23 23:54:32

这是基于@Manfred的solution的修改。我使用Command而不是event

XAML:

<DataGrid ItemsSource="{Binding Students}" AutoGenerateColumns="True" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.HeaderTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding DataContext.IsAllSelected, RelativeSource={RelativeSource AncestorType=DataGrid}}" Command="{Binding DataContext.CheckAllStudentsCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
                </DataTemplate>
            </DataGridTemplateColumn.HeaderTemplate>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}" Command="{Binding DataContext.CheckStudentCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

ViewModel:

public class MainWindowViewModel : INotifyPropertyChanged
{
    private List<Student> students;

    public List<Student> Students
    {
        get { return students; }
        set { students = value; OnPropertyChanged(); }
    }

    private bool? isAllSelected;

    public bool? IsAllSelected
    {
        get { return isAllSelected; }
        set { isAllSelected = value; OnPropertyChanged(); }
    }

    public RelayCommand CheckStudentCommand { get; private set; }
    public RelayCommand CheckAllStudentsCommand { get; private set; }

    public MainWindowViewModel()
    {
        Students = new List<Student>() { new Student { Name = "Walter" }, new Student { Name = "Jenny" }, new Student { Name = "Joe" } };
        CheckStudentCommand = new RelayCommand(OnCheckStudent);
        CheckAllStudentsCommand = new RelayCommand(OnCheckAllStudents);
        IsAllSelected = false;
    }

    private void OnCheckAllStudents()
    {
        if (IsAllSelected == true)
            Students.ForEach(x => x.IsChecked = true);
        else
            Students.ForEach(x => x.IsChecked = false);
    }

    private void OnCheckStudent()
    {
        if (Students.All(x => x.IsChecked))
            IsAllSelected = true;
        else if (Students.All(x => !x.IsChecked))
            IsAllSelected = false;
        else
            IsAllSelected = null;
    }

    public event PropertyChangedEventHandler PropertyChanged;

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

源代码可在here上找到

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48955781

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档