WPF 选择 DataGrid 中的所有 CheckBox [英] WPF Select all CheckBox in a DataGrid
问题描述
我正在尝试选择 DataGrid 中的所有 CheckBox,但使用下面的代码没有得到任何结果
这是我在单击主 CheckBox 时调用的函数
private void CheckUnCheckAll(object sender, RoutedEventArgs e){CheckBox chkSelectAll = ((CheckBox)sender);if (chkSelectAll.IsChecked == true){dgUsers.Items.OfType().ToList().ForEach(x => x.IsChecked = true);}别的{dgUsers.Items.OfType().ToList().ForEach(x => x.IsChecked = false);}}
dgUsers 是 DataGrid,但我意识到找到了任何复选框.
这是我用来在数据网格中创建复选框的 XAML
<DataGridCheckBoxColumn x:Name="col0" HeaderStyle="{StaticResource ColumnHeaderGripperStyle}"><DataGridCheckBoxColumn.HeaderTemplate><数据模板><CheckBox Click="CheckUnCheckAll" ></复选框></数据模板></DataGridCheckBoxColumn.HeaderTemplate></DataGridCheckBoxColumn><DataGrid.Columns>
这是我的 DataGrid 的图片
有没有办法以编程方式选择所有复选框?
编辑我已经尝试按照
执行此操作的正确位置是在您的 ViewModel 中.您的 CheckBox 可以具有三种状态,您希望使用所有这些状态:
- 已检查 - 每个项目都已检查
- 未选中 - 未选中任何项目
- 不确定 - 有些项目被检查,有些没有
您需要在选中/取消选中某个项目时更新 CheckBox,并在更改 CheckBox 时更新所有项目 - 仅实施这种方法会使 CheckBox 处于无效状态,这可能会对用户体验产生负面影响.我的建议:一路走好并正确实施.为此,您需要知道是哪个导致了更改 - 条目的 CheckBox 或标题中的 CheckBox.
这是我的做法:
首先,您的项目需要一个 ViewModel,我在这里使用了一个非常简化的模型,它只包含 IsChecked
属性.
公共类条目:INotifyPropertyChanged{私人布尔_isChecked;public bool IsChecked{得到 =>_isChecked;放{如果(值 == _isChecked)返回;_isChecked = 值;OnPropertyChanged();}}公共事件 PropertyChangedEventHandler PropertyChanged;[NotifyPropertyChangedInvocator]protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}
您的主 ViewModel 将包含所有项目的集合.每当项目的 IsChecked
属性发生变化时,您都必须检查 所有 项目是否已选中/未选中,并更新标题中的 CheckBox(或者更确切地说是其数据源的值).
公共类 ViewModel : INotifyPropertyChanged{公共列表<条目>参赛作品{得到 =>_条目;放{if (Equals(value, _entries)) 返回;_entries = 值;OnPropertyChanged();}}公共视图模型(){//只是一些演示数据条目 = 新列表<条目>{新的条目(),新的条目(),新的条目(),新的条目()};//确保监听更改.//如果您添加/删除项目,也不要忘记添加/删除事件处理程序foreach(条目中的条目){entry.PropertyChanged += EntryOnPropertyChanged;}}私有无效 EntryOnPropertyChanged(对象发送者,PropertyChangedEventArgs args){//仅重新检查 IsChecked 属性是否更改if(args.PropertyName == nameof(Entry.IsChecked))重新检查AllSelected();}私有无效 AllSelectedChanged(){//这个变化是由其他变化引起的吗?//返回所以我们不会把事情搞砸如果(_allSelectedChanging)返回;尝试{_allSelectedChanging = true;//这当然可以简化if (AllSelected == true){foreach(条目中的条目公社)kommune.IsChecked = true;}否则如果(AllSelected == false){foreach(条目中的条目公社)kommune.IsChecked = false;}}最后{_allSelectedChanging = false;}}私有无效 RecheckAllSelected(){//这个变化是由其他变化引起的吗?//返回所以我们不会把事情搞砸如果(_allSelectedChanging)返回;尝试{_allSelectedChanging = true;if (Entries.All(e => e.IsChecked))AllSelected = true;否则 if (Entries.All(e => !e.IsChecked))AllSelected = false;别的AllSelected = null;}最后{_allSelectedChanging = false;}}公共布尔?全部选中{得到 =>_allSelected;放{如果(值 == _allSelected)返回;_allSelected = 值;//设置所有其他复选框AllSelectedChanged();OnPropertyChanged();}}私人布尔_allSelectedChanging;私人列表<条目>_条目;私人布尔?_allSelected;公共事件 PropertyChangedEventHandler PropertyChanged;[NotifyPropertyChangedInvocator]protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}
演示 XAML:
<DataGrid.Columns><DataGridCheckBoxColumn Binding="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}"><DataGridCheckBoxColumn.HeaderTemplate><数据模板><CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:MainWindow}, Path=ViewModel.AllSelected}">全选</CheckBox></数据模板></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:
- Checked - Every item is checked
- Unchecked - No item is checked
- 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 中的所有 CheckBox的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!