[英]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<CheckBox>().ToList().ForEach(x => x.IsChecked = true);
}
else
{
dgUsers.Items.OfType<CheckBox>().ToList().ForEach(x => x.IsChecked = false);
}
}
dgUsers是DataGrid,但我發現任何復選框都找到了。
這是我正在使用的XAML在數據網格中創建CheckBox
<DataGrid.Columns>
<DataGridCheckBoxColumn x:Name="col0" HeaderStyle="{StaticResource ColumnHeaderGripperStyle}">
<DataGridCheckBoxColumn.HeaderTemplate>
<DataTemplate>
<CheckBox Click="CheckUnCheckAll" >
</CheckBox>
</DataTemplate>
</DataGridCheckBoxColumn.HeaderTemplate>
</DataGridCheckBoxColumn>
<DataGrid.Columns>
這是我的DataGrid的圖片
有沒有辦法以編程方式選擇所有復選框?
編輯我已經嘗試按照這個步驟
你可以看到我的代碼是相同的,但對我不起作用
TLDR; 這就是你想要的,代碼如下:
執行此操作的適當位置將在ViewModel中。 您的CheckBox可以有三種狀態,所有這些狀態都要使用:
每當檢查/取消選中項目時,您都希望更新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
屬性發生更改時,您必須檢查是否已選中/取消選中所有項目,並更新標題中的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>
你在你的例子中做的是迭代數據項而不是通過控件(我想你沒有像ItemsSource那樣的控件)。
在您發布的鏈接中, YourClass
是ViewModel中的類,網格行的數據對象。
這個應該可以使用最少的代碼更改(但我更喜歡在ViewModel中處理它與CheckUncheckCommand + IsChecked
綁定到CommandParameter
):
<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;
}
}
這是基於@Manfred 解決方案的修改。 我使用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>
視圖模型:
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));
}
}
源代碼可在此處獲得
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.