I'm trying to select all CheckBox in a DataGrid but I didn't get any result using this code bellow
我正在尝试在DataGrid中选择所有CheckBox,但我没有使用此代码获得任何结果
This is the function that I'm calling when the main CheckBox is clicked
这是我在单击主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);
}
else
{
dgUsers.Items.OfType().ToList().ForEach(x => x.IsChecked = false);
}
}
dgUsers is the DataGrid but as I realize any checkbox is found.
dgUsers是DataGrid,但我发现任何复选框都找到了。
This is the XAML that I'm using tho create the CheckBox in the datagrid
这是我正在使用的XAML在数据网格中创建CheckBox
And this is the picture of my DataGrid
这是我的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
你可以看到我的代码是相同的,但对我不起作用
11
TLDR; This is what you want, code below:
TLDR;这就是你想要的,代码如下:
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:
执行此操作的适当位置将在ViewModel中。您的CheckBox可以有三种状态,所有这些状态都要使用:
已选中 - 已检查每个项目
未选中 - 未选中任何项目
不确定 - 有些项目已经过检查,有些则没有
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.
每当检查/取消选中项目时,您都希望更新CheckBox,并在更改CheckBox时更新所有项目 - 只实现这一方法会使CheckBox处于无效状态,这可能会对用户体验产生负面影响。我的建议:一路走好并妥善实施。要做到这一点,你需要知道导致更改的内容 - 条目的CheckBox或标题中的CheckBox。
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.
首先,您需要一个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));
}
}
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).
您的主ViewModel将包含所有项目的集合。每当项目的IsChecked属性发生更改时,您必须检查是否已选中/取消选中所有项目,并更新标题中的CheckBox(或更确切地说是其数据源的值)。
public class ViewModel : INotifyPropertyChanged
{
public List Entries
{
get => _entries;
set
{
if (Equals(value, _entries)) return;
_entries = value;
OnPropertyChanged();
}
}
public ViewModel()
{
// Just some demo data
Entries = new List
{
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 _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:
Select All
2
What you do in your example is iterating through data item not through the controls(I suppose you have no controls as ItemsSource).
In the link you have posted YourClass
is the class from ViewModel, data object for grid's row.
你在你的例子中做的是迭代数据项而不是通过控件(我想你没有像ItemsSource那样的控件)。在您发布的链接中,YourClass是ViewModel中的类,网格行的数据对象。
This one should work with minimal code changes on your side(but I would prefer to handle it in the ViewModel with something like CheckUncheckCommand + binding of IsChecked
to the CommandParameter
):
这个应该可以使用最少的代码更改(但我更喜欢在ViewModel中处理它,例如CheckUncheckCommand + IsChecked绑定到CommandParameter):
private void CheckUnCheckAll(object sender, RoutedEventArgs e)
{
var chkSelectAll = sender as CheckBox;
var firstCol = dgUsers.Columns.OfType().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;
}
}