实现效果如下:
界面层
<DataGrid ItemsSource="{Binding Items1}" CanUserAddRows="False"
AutoGenerateColumns="False" HeadersVisibility="All">
<DataGrid.Resources>
<model:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="User" Binding="{Binding SectionName}" IsReadOnly="True"
ElementStyle="{StaticResource MaterialDesignDataGridTextColumnStyle}"
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}">
</DataGridTextColumn>
<DataGridCheckBoxColumn
Binding="{Binding IsSelected1, UpdateSourceTrigger=PropertyChanged}"
ElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnStyle}"
EditingElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnEditingStyle}">
<DataGridCheckBoxColumn.Header>
<Border Background="Transparent">
<CheckBox Content="Admin" HorizontalContentAlignment="Left" IsChecked="{Binding Data.IsAllItems1Selected , Source={StaticResource DataContextProxy}}" />
</Border>
</DataGridCheckBoxColumn.Header>
<DataGridCheckBoxColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</DataGridCheckBoxColumn.HeaderStyle>
</DataGridCheckBoxColumn>
<DataGridCheckBoxColumn
Binding="{Binding IsSelected2, UpdateSourceTrigger=PropertyChanged}"
ElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnStyle}"
EditingElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnEditingStyle}">
<DataGridCheckBoxColumn.Header>
<Border Background="Transparent">
<CheckBox Content="Engineer" HorizontalContentAlignment="Left" IsChecked="{Binding Data.IsAllItems2Selected , Source={StaticResource DataContextProxy}}" />
</Border>
</DataGridCheckBoxColumn.Header>
<DataGridCheckBoxColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</DataGridCheckBoxColumn.HeaderStyle>
</DataGridCheckBoxColumn>
<DataGridCheckBoxColumn
Binding="{Binding IsSelected3, UpdateSourceTrigger=PropertyChanged}"
ElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnStyle}"
EditingElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnEditingStyle}">
<DataGridCheckBoxColumn.Header>
<Border Background="Transparent">
<CheckBox Content="Technician" HorizontalContentAlignment="Left" IsChecked="{Binding Data.IsAllItems3Selected , Source={StaticResource DataContextProxy}}" />
</Border>
</DataGridCheckBoxColumn.Header>
<DataGridCheckBoxColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</DataGridCheckBoxColumn.HeaderStyle>
</DataGridCheckBoxColumn>
<DataGridCheckBoxColumn
Binding="{Binding IsSelected4, UpdateSourceTrigger=PropertyChanged}"
ElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnStyle}"
EditingElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnEditingStyle}">
<DataGridCheckBoxColumn.Header>
<Border Background="Transparent">
<CheckBox Content="Operator" HorizontalContentAlignment="Left" IsChecked="{Binding Data.IsAllItems4Selected , Source={StaticResource DataContextProxy}}" />
</Border>
</DataGridCheckBoxColumn.Header>
<DataGridCheckBoxColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</DataGridCheckBoxColumn.HeaderStyle>
</DataGridCheckBoxColumn>
</DataGrid.Columns>
</DataGrid>
model层
public class SelectViewModel2 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private bool _isSelected1;
public bool IsSelected1
{
get => _isSelected1;
set
{
if (_isSelected1 == value) return;
_isSelected1 = value;
OnPropertyChanged();
}
}
private bool _isSelected2;
public bool IsSelected2
{
get => _isSelected2;
set
{
if (_isSelected2 == value) return;
_isSelected2 = value;
OnPropertyChanged();
}
}
private bool _isSelected3;
public bool IsSelected3
{
get => _isSelected3;
set
{
if (_isSelected3 == value) return;
_isSelected3 = value;
OnPropertyChanged();
}
}
private bool _isSelected4;
public bool IsSelected4
{
get => _isSelected4;
set
{
if (_isSelected4 == value) return;
_isSelected4 = value;
OnPropertyChanged();
}
}
private string? _sectionName;
public string? SectionName
{
get => _sectionName;
set
{
if (_sectionName == value) return;
_sectionName = value;
OnPropertyChanged();
}
}
}
public class GridsViewModel2 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public ObservableCollection<SelectViewModel2> Items1 { get; }
public GridsViewModel2()
{
Items1 = CreateData();
foreach (var model in Items1)
{
model.PropertyChanged += (sender, args) =>
{
if (args.PropertyName == nameof(SelectViewModel2.IsSelected1))
OnPropertyChanged(nameof(IsAllItems1Selected));
if (args.PropertyName == nameof(SelectViewModel2.IsSelected2))
OnPropertyChanged(nameof(IsAllItems2Selected));
if (args.PropertyName == nameof(SelectViewModel2.IsSelected3))
OnPropertyChanged(nameof(IsAllItems3Selected));
if (args.PropertyName == nameof(SelectViewModel2.IsSelected4))
OnPropertyChanged(nameof(IsAllItems4Selected));
};
}
}
public bool? IsAllItems1Selected
{
get
{
var selected = Items1.Select(item => item.IsSelected1).Distinct().ToList();
return selected.Count == 1 ? selected.Single() : (bool?)null;
}
set
{
if (value.HasValue)
{
SelectAll(value.Value, Items1,1);
OnPropertyChanged();
}
}
}
public bool? IsAllItems2Selected
{
get
{
var selected = Items1.Select(item => item.IsSelected2).Distinct().ToList();
return selected.Count == 1 ? selected.Single() : (bool?)null;
}
set
{
if (value.HasValue)
{
SelectAll(value.Value, Items1,2);
OnPropertyChanged();
}
}
}
public bool? IsAllItems3Selected
{
get
{
var selected = Items1.Select(item => item.IsSelected3).Distinct().ToList();
return selected.Count == 1 ? selected.Single() : (bool?)null;
}
set
{
if (value.HasValue)
{
SelectAll(value.Value, Items1,3);
OnPropertyChanged();
}
}
}
public bool? IsAllItems4Selected
{
get
{
var selected = Items1.Select(item => item.IsSelected4).Distinct().ToList();
return selected.Count == 1 ? selected.Single() : (bool?)null;
}
set
{
if (value.HasValue)
{
SelectAll(value.Value, Items1,4);
OnPropertyChanged();
}
}
}
private static void SelectAll(bool select, IEnumerable<SelectViewModel2> models,int nColumn)
{
foreach (var model in models)
{
switch(nColumn)
{
case 1:
model.IsSelected1 = select;
break;
case 2:
model.IsSelected2 = select;
break;
case 3:
model.IsSelected3 = select;
break;
case 4:
model.IsSelected4 = select;
break;
}
}
}
private static ObservableCollection<SelectViewModel2> CreateData()
{
return new ObservableCollection<SelectViewModel2>
{
new SelectViewModel2
{
SectionName="001"
},
new SelectViewModel2
{
SectionName="002"
},
new SelectViewModel2
{
SectionName="003"
},
new SelectViewModel2
{
SectionName="004"
}
};
}
}
public class BindingProxy : Freezable
{
protected override Freezable CreateInstanceCore() => new BindingProxy();
public object? Data
{
get => GetValue(DataProperty);
set => SetValue(DataProperty, value);
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}