wpf研究之道——datagrid控件及样式
一、datagrid继承体系
“想要说些什么 又不知从何说起”,每当想要写一些关于wpf的文章,总是沉思良久,怕自己写不好。今天我想要说的是wpf中datagrid控件。我们先来看看它在整个类的层次结构:
图1 wpf 图1.1 winform
wpf和winform顺便作个比较,看看Control之上的结构:
图2 wpf 图2.2 winform
从以上四幅图中,可以看出wpf的继承层次深一些。wpf中的DispatcherObject,用于控制UI界面的修改,在多线程场景下,如果其它线程需要修改界面,就需要调用它。如:
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,委托)
1、 每个wpf对象都可以调用到Dispatcher对象,从继承图上可以出看出来。Dispatcher对象把委托加入到内部的执行队列中,然后根据优先级,在不同的时间内,由UI线程执行。通过查阅相关资料,一个Dispatcher对象关联了一个UI线程,相反一个UI线程可能拥有多个Dispatcher对象。
2、winform中的MarshalByRefObject,它允许Control对象跨进程被调用。
二、datagrid样式
<!--dataGrid通用样式--> <Style TargetType="DataGrid"> <!--网格线颜色--> <Setter Property="CanUserResizeColumns" Value="True"/> <Setter Property="Background" Value="#edf2f8" /> <Setter Property="AlternationCount" Value="2" /> <Setter Property="BorderBrush" Value="#d8e6f3" /> <Setter Property="HorizontalGridLinesBrush"> <Setter.Value> <SolidColorBrush Color="#d8e6f3"/> </Setter.Value> </Setter> <Setter Property="VerticalGridLinesBrush" Value="{x:Null}"/> </Style>
<Style TargetType="DataGridColumnHeader" x:Key="ColumnBaseStyle"> <Setter Property="SnapsToDevicePixels" Value="True" /> <Setter Property="MinHeight" Value="40" /> <Setter Property="Foreground" Value="#323433" /> <Setter Property="FontSize" Value="13" /> <Setter Property="FontWeight" Value="Bold" /> <Setter Property="Cursor" Value="Hand" /> <Setter Property="Height" Value="40"/> <Setter Property="HorizontalContentAlignment" Value="Left" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="IsTabStop" Value="False" /> <Setter Property="BorderBrush" Value="#d9e5f3"/> <Setter Property="BorderThickness" Value="0 0 1 0"/> <Setter Property="Padding" Value="5 0"/> </Style>
<!--标题栏样式--> <Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource ColumnBaseStyle}"> </Style>
<!--行样式触发--> <Style TargetType="DataGridRow"> <Setter Property="Background" Value="White" /> <Setter Property="Height" Value="40"/> <Setter Property="Foreground" Value="Black" /> <Style.Triggers> <!--隔行变色--> <Trigger Property="ItemsControl.AlternationIndex" Value="0"> <Setter Property="Background" Value="#edf2f8" /> </Trigger> <Trigger Property="ItemsControl.AlternationIndex" Value="1"> <Setter Property="Background" Value="White" /> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="#cde7ff"/> </Trigger> <Trigger Property="IsSelected" Value="True"> <Setter Property="Foreground" Value="Black"/> <Setter Property="Background" Value="#cde7ff"/> </Trigger> </Style.Triggers> </Style>
<Style TargetType="DataGridCell" x:Key="CellBaseStyle"> <Setter Property="Padding" Value="5 0"/> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="Foreground" Value="Black"/> <Setter Property="Background" Value="#cde7ff"/> </Trigger> </Style.Triggers> </Style> <!--单元格样式触发--> <Style TargetType="DataGridCell" BasedOn="{StaticResource CellBaseStyle}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="DataGridCell"> <Border Background="{TemplateBinding Background}" SnapsToDevicePixels="True" BorderThickness="0" Height="{TemplateBinding Tag}"> <TextBlock ToolTip="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="{TemplateBinding Padding}" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}" TextTrimming="CharacterEllipsis" /> </Border> </ControlTemplate> </Setter.Value> </Setter> </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>
<Style TargetType="DataGridColumnHeader" x:Key="documentColumnHead" BasedOn="{StaticResource ColumnBaseStyle}"> <Setter Property="HorizontalContentAlignment" Value="Left" /> </Style> <Style TargetType="DataGridCell" x:Key="documentCellStyle" BasedOn="{StaticResource CellBaseStyle}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="DataGridCell"> <Border Background="{TemplateBinding Background}" SnapsToDevicePixels="True" BorderThickness="0" Height="{TemplateBinding Tag}"> <TextBlock ToolTip="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="{TemplateBinding Padding}" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text}" TextTrimming="CharacterEllipsis" /> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="DataGridCell" x:Key="resultCellStyle" BasedOn="{StaticResource CellBaseStyle}"> <Setter Property="BorderThickness" Value="0"/> </Style> <Style TargetType="DataGridCell" x:Key="OperCellStyle" BasedOn="{StaticResource CellBaseStyle}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="DataGridCell"> <ContentPresenter HorizontalAlignment="Left" VerticalAlignment="Center"/> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--checkbox列头样式和列单元格样式--> <Style x:Key="DataGridCheckboxCellStyle1" TargetType="{x:Type DataGridCell}"> <Setter Property="ContentTemplate" Value="{DynamicResource CheckboxDataTemplate1}"/> <Setter Property="Template" Value="{DynamicResource DataGridCheckboxCellControlTemplate1}"/> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="Background" Value="{x:Null}"/> <Setter Property="BorderBrush" Value="{x:Null}"/> </Trigger> </Style.Triggers> </Style> <Style x:Key="DataGridCheckboxColumnHeaderStyle1" TargetType="{x:Type DataGridColumnHeader}"> <Setter Property="Padding" Value="13 0 0 0"/> <Setter Property="Background" Value="White"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="ContentTemplate" Value="{DynamicResource CheckboxDataTemplate1}"/> <Setter Property="HorizontalAlignment" Value="Stretch"/> <Setter Property="VerticalAlignment" Value="Stretch"/> </Style>
<DataTemplate x:Key="CheckboxDataTemplate1"> <Grid> <CheckBox x:Name="chkSelected" HorizontalAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center" Click="chkSelected_OnClick" IsThreeState="False" IsChecked="{Binding IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> </Grid> </DataTemplate>
从datagrid、DataGridColumnHeader、DataGridRow、DataGridCell到特殊的列,如Checkbox列样式是层层递进,越来越精细,一个样式可以采用BaseOn继承父样式。
1、ControlTemplate
通过ControlTemplate控制控件的外观,比如我可以让一个button长成这样: 通过设置Template的值,而设定ControlTemplate。wpf UI中有两棵树,一个是visualTree(可视树),另一个是logicTree(逻辑树)。如果你在vs中,快速监视某一个控件的话,就可以显示出它的可视树。ControlTemplate所描述的控件内部结构正是属于可视树的范畴。那什么是逻辑树呢?就是你在代码中看到的控件组成的一棵树。显然,可视树包含了逻
辑树。你可以认为可视树是对一个控件的精细描述。比如,我们说,一个人是由眼睛、鼻子、耳朵等等构成,这种描述就是属于逻辑树,至于对眼睛、鼻子、耳朵的内部构造描述,这属于可视树。
2、DataTemplate
数据模板,它用来控制对象在控件上的绑定。
这是一个checkbox列头的数据绑定,绑定了对象的IsSelected属性。
3、触发器
当一个单元格被选中的时候,它的前景色和背景色的变化。隔行变色的实现。下面是按钮的触发器,当鼠标经过和按下的时候,样式变化。