C# 如何通过WPF DataGrid中的DataGrid Header CheckBox选择列的所有CheckBox
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13081725/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Select All CheckBox of a Column by DataGrid Header CheckBox in WPF DataGrid
提问by Avinash Singh
I have a DataGrid with one CheckBoxColumn. In the header of that CheckBoxColumn I have added a CheckBox to Select all CheckBoxes of that Datagrid Row.
我有一个带有一个 CheckBoxColumn 的 DataGrid。在 CheckBoxColumn 的标题中,我添加了一个 CheckBox 来选择该 Datagrid 行的所有复选框。
How can I achieve that?
我怎样才能做到这一点?
My XAML Code for WPF dataGrid:
我的 WPF 数据网格 XAML 代码:
<DataGrid AutoGenerateColumns="False" CanUserAddRows="False" Grid.RowSpan="2" Height="130" HorizontalAlignment="Left" IsReadOnly="False" Margin="189,340,0,0" Name="dgCandidate" TabIndex="7" VerticalAlignment="Top" Width="466" Grid.Row="1" >
<DataGrid.Columns>
<DataGridTextColumn x:Name="colCandidateID" Binding="{Binding CandidateID}" Header="SlNo" MinWidth="20" IsReadOnly="True" />
<DataGridTextColumn x:Name="colRegistraion" Binding="{Binding RegisterNo}" Header="Reg. No." IsReadOnly="True" />
<DataGridTextColumn x:Name="colCandidate" Binding="{Binding CandidateName}" Header="Name" MinWidth="250" IsReadOnly="True" />
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<CheckBox Name="chkSelectAll" Checked="chkSelectAll_Checked" Unchecked="chkSelectAll_Unchecked"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate >
<DataTemplate >
<CheckBox x:Name="colchkSelect1" Checked="colchkSelect1_Checked" Unchecked="colchkSelect1_Unchecked" ></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
采纳答案by Bizhan
Convert your Candidate class into something like this:
将你的 Candidate 类转换成这样:
public class Candidate : DependencyObject
{
//CandidateID Dependency Property
public int CandidateID
{
get { return (int)GetValue(CandidateIDProperty); }
set { SetValue(CandidateIDProperty, value); }
}
public static readonly DependencyProperty CandidateIDProperty =
DependencyProperty.Register("CandidateID", typeof(int), typeof(Candidate), new UIPropertyMetadata(0));
//RegisterNo Dependency Property
public int RegisterNo
{
get { return (int)GetValue(RegisterNoProperty); }
set { SetValue(RegisterNoProperty, value); }
}
public static readonly DependencyProperty RegisterNoProperty =
DependencyProperty.Register("RegisterNo", typeof(int), typeof(Candidate), new UIPropertyMetadata(0));
//CandidateName Dependency Property
public string CandidateName
{
get { return (string)GetValue(CandidateNameProperty); }
set { SetValue(CandidateNameProperty, value); }
}
public static readonly DependencyProperty CandidateNameProperty =
DependencyProperty.Register("CandidateName", typeof(string), typeof(Candidate), new UIPropertyMetadata(""));
//BooleanFlag Dependency Property
public bool BooleanFlag
{
get { return (bool)GetValue(BooleanFlagProperty); }
set { SetValue(BooleanFlagProperty, value); }
}
public static readonly DependencyProperty BooleanFlagProperty =
DependencyProperty.Register("BooleanFlag", typeof(bool), typeof(Candidate), new UIPropertyMetadata(false));
}
in MainWindow.xaml:
在 MainWindow.xaml 中:
<DataGrid ItemsSource="{Binding CandidateList}">
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding CandidateID}"/>
<DataGridTextColumn Header="RegNr" Binding="{Binding RegisterNo}"/>
<DataGridTextColumn Header="Name" Binding="{Binding CandidateName}"/>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Checked"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<CheckBox IsChecked="{Binding BooleanFlag}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
in MainWindow.xaml.cs:
在 MainWindow.xaml.cs 中:
public MainWindow()
{
DataContext = this;
CandidateList.Add(new Candidate()
{
CandidateID = 1,
CandidateName = "Hyman",
RegisterNo = 123,
BooleanFlag = true
});
CandidateList.Add(new Candidate()
{
CandidateID = 2,
CandidateName = "Jim",
RegisterNo = 234,
BooleanFlag = false
});
InitializeComponent();
}
//List Observable Collection
private ObservableCollection<Candidate> _candidateList = new ObservableCollection<Candidate>();
public ObservableCollection<Candidate> CandidateList { get { return _candidateList; } }
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
foreach (var item in CandidateList)
{
item.BooleanFlag = true;
}
}
private void UnheckBox_Checked(object sender, RoutedEventArgs e)
{
foreach (var item in CandidateList)
{
item.BooleanFlag = false;
}
}
回答by blindmeis
I have added CheckBox to Select all CheckBox in Datagrid Row
我添加了 CheckBox 以选择 Datagrid Row 中的所有 CheckBox
if you mean select all checkbox in datagrid column, then i would say: simply update your itemssource collection with checked/unchecked.
如果您的意思是选择 datagrid列中的所有复选框,那么我会说:只需使用选中/未选中状态更新您的 itemssource 集合。
public bool SelectAll
{
get{return this._selectAll;}
set
{
this._selectAll = value;
this.MyItemsSourceCollection.ForEach(x=>x.MyRowCheckProperty=value);
this.OnPropertyChanged("SelectAll");
}
}
xaml
xml
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<CheckBox isChecked="{Binding SelectAll}"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate >
<DataTemplate >
<CheckBox IsChecked="{Binding MyRowCheckProperty}"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
i dunno if the xaml bindings are right, but i hope you can see my intention
我不知道 xaml 绑定是否正确,但我希望你能看到我的意图
回答by ComeIn
Strictly speaking the model should not know about the view and so the solution proposed by blindmeis, where the model change is updating every row in the datagrid, breaks the MVVM/Presentation Design pattern. Remember that in MVVM the dependency flow is View -> ViewModel -> Model so if you are referencing controls in your view model (or control codebehind) then you have effectively broken the pattern and you will probably run into issues further down the track.
严格来说,模型不应该知道视图,因此,blinmeis 提出的解决方案,其中模型更改是更新数据网格中的每一行,打破了 MVVM/演示设计模式。请记住,在 MVVM 中,依赖流是 View -> ViewModel -> Model,因此如果您在视图模型(或控件代码隐藏)中引用控件,那么您已经有效地打破了模式,并且您可能会在轨道上进一步遇到问题。
回答by satnhak
It turns out that this is quite a lot harder to get right than one would hope.
事实证明,要做到这一点比人们希望的要困难得多。
The first problem is that you can't just bind the view model to the column header because it doesn't have the view model as its data context, so you need a binding proxy to correctly route the binding to the view model.
第一个问题是你不能仅仅将视图模型绑定到列标题,因为它没有视图模型作为它的数据上下文,所以你需要一个绑定代理来正确地将绑定路由到视图模型。
public class BindingProxy : Freezable
{
public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
"Data",
typeof(object),
typeof(BindingProxy),
new UIPropertyMetadata(null));
public object Data
{
get { return this.GetValue(DataProperty); }
set { this.SetValue(DataProperty, value); }
}
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
}
Now create a binding proxy in your data grid's resources:
现在在数据网格的资源中创建一个绑定代理:
<DataGrid.Resources>
<aon:BindingProxy
x:Key="DataContextProxy"
Data="{Binding}" />
</DataGrid.Resources>
Then the column needs to be defined as:
然后需要将列定义为:
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<CheckBox
Command="{Binding
Data.SelectAllCommand,
Source={StaticResource DataContextProxy}}"
IsChecked="{Binding
Data.AreAllSelected,
Mode=OneWay,
Source={StaticResource DataContextProxy},
UpdateSourceTrigger=PropertyChanged}"
IsThreeState="True" />
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
IsChecked="{Binding
Path=IsSelected,
UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Note that there needs to be a binding to both the check box's IsCheckeddependency property and its Commandproperty and the IsCheckedbinding is OneWay. The IsCheckedbinding gets the check box to display the current state of the items and the Commandbinding performs the bulk selection. You need both.
请注意,需要绑定到复选框的IsChecked依赖属性及其Command属性,并且IsChecked绑定是OneWay。的IsChecked结合得到的复选框以显示项目和当前状态的Command结合进行批量选择。你需要两者。
Now in the view model:
现在在视图模型中:
public bool? AreAllSelected
{
get
{
return this.Items.All(candidate => candidate.IsSelected)
? true
: this.Items.All(candidate => !candidate.IsSelected)
? (bool?)false
: null;
}
set
{
if (value != null)
{
foreach (var item in this.Items)
{
item.IsSelected = value.Value;
}
}
this.RaisePropertyChanged();
}
}
And the SelectAllCommandproperty is an implementation of ICommandwhere the Executemethod is:
该SelectAllCommand属性是方法ICommand所在位置的实现Execute:
public void Execute(object parameter)
{
var allSelected = this.AreAllSelected;
switch (allSelected)
{
case true:
this.AreAllSelected = false;
break;
case false:
case null:
this.AreAllSelected = true;
break;
}
}
Finally your row item view models (i.e. the things in Items) need to raise PropertyChangedon the main view model each time the value of IsSelectedchanges. How you do that is pretty much up to you.
最后,每次更改值时,您的行项目视图模型(即 中的内容Items)都需要PropertyChanged在主视图模型上提高IsSelected。你如何做到这一点完全取决于你。

