当你使用 MVVM 时,你必须知道什么是数据,什么是严格的 UI。
您SelectedItems
将成为数据的一部分,还是只是您的 UI?
如果它是您数据的一部分,那么您确实应该IsSelected
在数据模型上拥有一个属性,即使这意味着扩展数据类以包含一个属性,或者创建一个仅包含andIsSelected
的包装类。第一个选项可能是首选,因为您可以保留,它使列绑定更简单。bool IsSelected
object MyDataItem
AutoGenerateColumns="True"
然后,您只需将您的绑定DataGridRow.SelectedItem
到IsSelected
数据项的属性:
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
但是,如果您SelectedItems
仅用于 UI,或者您在这种情况下由于某种原因破坏了 MVVM 模式,那么您可以创建未绑定CheckBox
并使用一些代码来确保CheckBox
正确同步到SelectedItem
.
我做了一个快速示例应用程序,我的代码如下所示:
首先,我只是CheckBox
使用DataGridTemplateColumn
. 这将在AutoGenerateColumns
列列表之前添加。
<DataGrid x:Name="TestDataGrid" ItemsSource="{Binding Test}"
SelectionMode="Extended" CanUserAddRows="False"
PreviewMouseLeftButtonDown="TestDataGrid_PreviewMouseLeftButtonDown_1">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="TestCheckBox"
PreviewMouseLeftButtonDown="CheckBox_PreviewMouseLeftButtonDown" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
其次,我向 中添加了一个PreviewMouseDown
事件以CheckBox
使其设置IsSelected
行的属性。
private void CheckBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var chk = (CheckBox)sender;
var row = VisualTreeHelpers.FindAncestor<DataGridRow>(chk);
var newValue = !chk.IsChecked.GetValueOrDefault();
row.IsSelected = newValue;
chk.IsChecked = newValue;
// Mark event as handled so that the default
// DataGridPreviewMouseDown doesn't handle the event
e.Handled = true;
}
它需要导航VisualTree
以找到DataGridRow
与单击的关联CheckBox
以选择它,并且为了让生活更轻松,我正在使用我博客上的一些自定义 VisualTreeHelpers 来查找DataGridRow
. 您可以使用相同的代码,也可以创建自己的方法来搜索VisualTree
.
最后,如果用户点击 以外的任何地方CheckBox
,我们希望禁用默认DataGrid
选择事件。这确保了该IsSelected
值仅在您单击 时才会更改CheckBox
。
有多种方法可以禁用不同级别的选择,但为了简单起见,DataGrid.PreviewMouseLeftButtonDown
如果用户没有点击CheckBox
.
private void TestDataGrid_PreviewMouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
{
var chk = VisualTreeHelpers.FindAncestor<CheckBox>((DependencyObject)e.OriginalSource, "TestCheckBox");
if (chk == null)
e.Handled = true;
}
我再次使用我的自定义VisualTreeHelpers来导航可视化树并确定是否单击了 CheckBox,如果用户单击了除CheckBox
.
至于您添加CheckBox
到SelectAll
或UnselectAll
项目的第二个请求,这将再次取决于您的选择是 UI 还是数据的一部分。
如果它是 UI 的一部分,只需在 中添加一个CheckBox
,DataGridTemplateColumn.HeaderTemplate
然后单击它时,循环浏览,在第一列中DataGrid.Rows
找到,然后选中或取消选中它。CheckBox
如果它是数据的一部分,您仍然可以做同样的事情(仅在 中设置绑定值DataGrid.Items
而不是CheckBox.IsChecked
from DataGrid.Rows
),或者您可以按照Adolfo Perez 的建议进行操作,并将其绑定到ViewModel
.