当您使用MVVM时,必须了解什么被认为是数据,什么是严格的UI。
您的SelectedItems是否将成为数据的一部分,还是仅限于UI?
如果它是数据的一部分,您真的应该在数据模型上拥有一个IsSelected属性,即使这意味着扩展数据类以包括一个IsSelected属性,或者创建一个仅包含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
同步。
我做了一个快速示例应用程序,这是我的代码:
首先,我只是使用DataGridTemplateColumn
将未绑定的CheckBox
列添加到列列表中。这将在AutoGenerateColumns
列列表之前添加。
<DataGrid x:Name="TestDataGrid" ItemsSource=""
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>
其次,我给 CheckBox
添加了一个 PreviewMouseDown
事件,使其设置行的 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;
e.Handled = true;
}
它需要导航
VisualTree
以找到与所点击的
CheckBox
相关联的
DataGridRow
以选择它,并且为了使生活更加轻松,我正在使用一些自定义
VisualTreeHelpers,在我的博客上来查找
DataGridRow
。您可以使用相同的代码,或者创建自己的搜索
VisualTree
方法。
最后,如果用户单击除
CheckBox
之外的任何地方,我们希望禁用默认的
DataGrid
选择事件。这确保了只有在单击
CheckBox
时
IsSelected
值才会发生变化。
有多种方法可以在不同级别上禁用此操作,但为了简单起见,我只是在用户没有单击
CheckBox
的情况下禁用了
DataGrid.PreviewMouseLeftButtonDown
事件。
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
添加到SelectAll
或UnselectAll
项中,这将再次取决于您的选择是UI的一部分还是数据的一部分。
如果它是UI的一部分,只需将CheckBox
添加到DataGridTemplateColumn.HeaderTemplate
中,当单击它时,循环遍历DataGrid.Rows
,查找第一列中的CheckBox
,并选中或取消选中它。
如果它是数据的一部分,您仍然可以做同样的事情(只需在
DataGrid.Items
中设置绑定值,而不是来自
DataGrid.Rows
的
CheckBox.IsChecked
),或者您可以像
Adolfo Perez suggested那样将其绑定到
ViewModel
上的属性。