有下面是实现思路:
1.继承INotifyPropertyChanged接口,实现OnPropertyChanged方法: public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary> /// Raises this object's PropertyChanged event. /// </summary> /// <param name="propertyName">The property that has a new value</param> protected void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler) { handler(this, new PropertyChangedEventArgs(propertyName)); } }
//..................
}
2. 实现viewModel, 添加IsSelected属性, 存储当前多选状态 private bool _isSelected = true;
public bool IsSelected { get { return _isSelected; }
set { _isSelected = value; OnPropertyChanged("IsSelected"); } }
3.在VM/Model准备好后, 我们接下来开始对DataGrid进行style自定义
4.准备checkbox的DataTemplate:
<DataTemplate x:Key="CheckboxDataTemplate1"> <Grid> <CheckBox x:Name="_chkSelected" Height="16" HorizontalAlignment="Center" VerticalAlignment="Center" Background="{x:Null}" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Click="_chkSelected_OnClick" IsThreeState="False" IsChecked="{Binding IsSelected, Mode=OneWay, FallbackValue=True}" /> </Grid> </DataTemplate>
此示例中checkbox只有简单的2种状态, 1)IsChecked属性绑定VM的IsSelected属性; 2)Mode为OneWay是因为我们需求是用户可以多选行然后点击某行头选中多行。此功能在Click事件中遍历当前所有选中的行,然后更改其VM的IsSelected属性。因此不需要TwoWay模式; 3)在Binding中添加了FallbackValue, 此属性指示当binding失败时给出的默认值。此例中因为DataTemplate也应用在列头, 而列头的DataContext和DataGridRow不同; 4)在Click事件处理函数中,判断当前点击的列头还是行头, 更改对应DataContext的IsSelected属性。 如: private void _chkSelected_OnClick(object sender, RoutedEventArgs e) { CheckBox chkSelected = e.OriginalSource as CheckBox; if (null == chkSelected) { return; }
var studyModel = chkSelected.DataContext as StudyModel;
bool isChecked = chkSelected.IsChecked.HasValue ? chkSelected.IsChecked.Value : true; FrameworkElement templateParent = chkSelected.TemplatedParent is FrameworkElement ? (chkSelected.TemplatedParent as FrameworkElement).TemplatedParent as FrameworkElement : null;
if (templateParent is DataGridColumnHeader) { MainViewModel mvm = this.DataContext as MainViewModel; if (null != mvm) { foreach (var sm in mvm.StudyList) { sm.IsSelected = isChecked; } } } else if (templateParent is DataGridCell) { if (null != studyModel && null != this._grdStudyList.SelectedItems && this._grdStudyList.SelectedItems.Contains(studyModel)) { foreach (var otherSelected in this._grdStudyList.SelectedItems.OfType<StudyModel>()) { otherSelected.IsSelected = isChecked; } } } }
其中MainViewModel为主VM, 其包含一个ObservableCollection<StudyModel> StudyList, 而StudyModel包含IsSelected属性, 二者都实现OnpropertyChanged方法; _grdStudyList为xaml中的DataGrid
5.应用DataTemplate到DataGridColumnHeader和DataGridCell, 如:
<Style x:Key="DataGridCheckboxColumnHeaderStyle1" TargetType="{x:Type DataGridColumnHeader}"> <Setter Property="ContentTemplate" Value="{DynamicResource CheckboxDataTemplate1}"/> <Setter Property="HorizontalAlignment" Value="Stretch"/> <Setter Property="VerticalAlignment" Value="Stretch"/> </Style>
<Style x:Key="DataGridCheckboxCellStyle1" TargetType="{x:Type DataGridCell}"> <Setter Property="Padding" Value="20,0"/> <Setter Property="ContentTemplate" Value="{DynamicResource CheckboxDataTemplate1}"/> <Setter Property="Background" Value="#FFC1C1C1"/> <Setter Property="BorderBrush" Value="{x:Null}"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="Template" Value="{DynamicResource DataGridCheckboxCellControlTemplate1}"/> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="Background" Value="#FFC1C1C1"/> <Setter Property="BorderBrush" Value="{x:Null}"/> </Trigger> </Style.Triggers> </Style>
<ControlTemplate x:Key="DataGridCheckboxCellControlTemplate1" TargetType="{x:Type DataGridCell}"> <Border
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True"> <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> </Border> </ControlTemplate>
6.应用CellStyle和HeaderStyle到DataGrid:
<DataGrid
x:Name="_grdStudyList"
ItemsSource="{Binding StudyList}"
AutoGenerateColumns="False"
FrozenColumnCount="1" Background="#FF999797">
<DataGrid.Columns>
<DataGridCheckBoxColumn
x:Name="_dtcSelected"
Header=""
HeaderStyle="{StaticResource DataGridCheckboxColumnHeaderStyle1}"
CellStyle="{StaticResource DataGridCheckboxCellStyle1}"
MinWidth="60" CanUserReorder="False" MaxWidth="60"/>