【发布时间】:2010-08-17 13:56:40
【问题描述】:
我通过覆盖其控件模板为我的 WPF 数据网格创建了一个自定义样式 - 没有什么不寻常的,只是复制了原始模板并对其进行了修改。不幸的是,当绘制网格时,我的 ViewModel 的完全限定类名显示在标题中(ViewModel 恰好是包含 DataGrid 的 UserControl 的 DataContext)。使用 Snoop,我缩小了模板中显示此类名称的元素的范围:
<DataGridColumnHeadersPresenter
Grid.Column="1"
Name="PART_ColumnHeadersPresenter"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>
这部分的可视化树如下所示:
PART_ColumnHeadersPresenter (DataGridColumnHeadersPresenter)
(Grid)
headerBorder (DataGridHeaderBorder)
(Border)
(TextBlock)
正是这个文本块包含了类名!所以问题是
- 为什么边框需要 TextBlock?
- 为什么用 DataContext 的类名初始化 TextBlock?
- DataGrid 级别是否有控制此 TextBlock 内容的属性?
附:为了回答下面的评论,我为 ItemSource 以及每一列指定了正确的路径:
<DataGrid
ItemsSource="{Binding Path=Orders, Mode=TwoWay}"
AutoGenerateColumns="False"
IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn
Header="Creation Time"
Binding="{Binding Path=CreationTime}"
CellStyle="{StaticResource LeftAlignedCellStyle}"
SortMemberPath="CreationTime">
</DataGridTextColumn>
...
</DataGrid.Columns>
</DataGrid>
我没有看到任何必须为列标题边框绑定 TextBlock 的地方。甚至不知道这有什么意义!
根据 Avatar 的评论,我正在分享我的整个模板。见下文:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Brushes.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!-- ColumnHeader Gripper Style -->
<Style x:Key="ColumnHeaderGripperStyle" TargetType="{x:Type Thumb}">
<Setter Property="Width" Value="8"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Cursor" Value="SizeWE"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- DataGridColumnHeader Style -->
<Style x:Key="DataGridColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Background" Value="{StaticResource HeaderBackgroundBrush}"/>
<Setter Property="Foreground" Value="{StaticResource HeaderForegroundBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource HeaderBorderBrush}" />
<Setter Property="BorderThickness" Value="0,1,0,1" />
<Setter Property="FontFamily" Value="Trebuchet MS" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<themes:DataGridHeaderBorder
x:Name="headerBorder"
SortDirection="{TemplateBinding SortDirection}"
IsHovered="{TemplateBinding IsMouseOver}"
IsPressed="{TemplateBinding IsPressed}"
IsClickable="{TemplateBinding CanUserSort}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding ="{TemplateBinding Padding}"
SeparatorVisibility="{TemplateBinding SeparatorVisibility}"
SeparatorBrush="{TemplateBinding SeparatorBrush}">
<Border BorderBrush="{StaticResource HeaderInnerBorderBrush}"
BorderThickness="0,1,0,0">
<TextBlock
Text="{Binding}" Margin="7,0,7,0"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
</Border>
</themes:DataGridHeaderBorder>
<Thumb x:Name="PART_LeftHeaderGripper"
HorizontalAlignment="Left"
Style="{StaticResource ColumnHeaderGripperStyle}"/>
<Thumb x:Name="PART_RightHeaderGripper"
HorizontalAlignment="Right"
Style="{StaticResource ColumnHeaderGripperStyle}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="headerBorder" Property="Background"
Value="{StaticResource HeaderHighlightedBackgoundBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="headerBorder" Property="Background"
Value="{StaticResource HeaderPressedBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Right Aligned DataGridColumnHeader Style-->
<Style x:Key="RightAlignedColumnHeaderStyle"
TargetType="{x:Type DataGridColumnHeader}"
BasedOn="{StaticResource DataGridColumnHeaderStyle}">
<Setter Property="HorizontalContentAlignment" Value="Right"/>
</Style>
<!-- Center Aligned DataGridColumnHeader Style-->
<Style x:Key="CenterAlignedColumnHeaderStyle"
TargetType="{x:Type DataGridColumnHeader}"
BasedOn="{StaticResource DataGridColumnHeaderStyle}">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
</Style>
<!-- DataGridRowHeader Gripper -->
<Style x:Key="RowHeaderGripperStyle" TargetType="{x:Type Thumb}">
<Setter Property="Height" Value="8"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Cursor" Value="SizeNS"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- DataGridRowHeader Style -->
<Style x:Key="{x:Type DataGridRowHeader}"
TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Background" Value="{StaticResource HeaderBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource HeaderBorderBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridRowHeader}">
<Grid>
<themes:DataGridHeaderBorder
x:Name="headerBorder"
IsSelected="{TemplateBinding IsRowSelected}"
IsHovered ="{TemplateBinding IsMouseOver}"
IsPressed="{TemplateBinding IsPressed}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1,0,1,1"
Padding ="{TemplateBinding Padding}"
Orientation="Horizontal"
SeparatorVisibility="{TemplateBinding SeparatorVisibility}"
SeparatorBrush="{TemplateBinding SeparatorBrush}">
<Border BorderBrush="{StaticResource HeaderInnerBorderBrush}"
BorderThickness="0,1,0,0">
<StackPanel Orientation="Horizontal">
<ContentPresenter
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Center"/>
<Control
SnapsToDevicePixels="false"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Path=(Validation.HasError), Converter={StaticResource bool2VisibilityConverter}}"
Template="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Path=ValidationErrorTemplate}" />
</StackPanel>
</Border>
</themes:DataGridHeaderBorder>
<Thumb x:Name="PART_TopHeaderGripper"
VerticalAlignment="Top"
Style="{StaticResource RowHeaderGripperStyle}"/>
<Thumb x:Name="PART_BottomHeaderGripper"
VerticalAlignment="Bottom"
Style="{StaticResource RowHeaderGripperStyle}"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="headerBorder" Property="Background"
Value="{StaticResource HeaderHighlightedBackgoundBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="headerBorder" Property="Background"
Value="{StaticResource HeaderPressedBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- DataGridElement Styles -->
<Style x:Key="DataGridElementStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="7 0 7 0" />
</Style>
<Style x:Key="LeftAlignedElementStyle" TargetType="{x:Type FrameworkElement}" BasedOn="{StaticResource DataGridElementStyle}">
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style x:Key="CenterAlignedElementStyle" TargetType="{x:Type FrameworkElement}" BasedOn="{StaticResource DataGridElementStyle}">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<Style x:Key="RightAlignedElementStyle" TargetType="{x:Type FrameworkElement}" BasedOn="{StaticResource DataGridElementStyle}">
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<!-- DataGridCell Styles -->
<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}">
<!-- Remove blue highlight when cell is selected -->
<Setter Property="Background" Value="Transparent" />
<!-- Don't change text color when cell is selected -->
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=Foreground}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="LeftAlignedCellStyle" TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource DataGridCellStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter Style="{StaticResource LeftAlignedElementStyle}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Center Aligned DataGridCell Style -->
<Style x:Key="CenterAlignedCellStyle" TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource DataGridCellStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter Style="{StaticResource CenterAlignedElementStyle}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Right Aligned DataGridCell Style -->
<Style x:Key="RightAlignedCellStyle" TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource DataGridCellStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter Style="{StaticResource RightAlignedElementStyle}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- SelectAllButton ControlTemplate -->
<ControlTemplate x:Key="SelectAllButtonTemplate" TargetType="{x:Type Button}">
<Grid>
<Rectangle x:Name="Border" SnapsToDevicePixels="True"
Stroke="{StaticResource HeaderBorderBrush}"
Fill="{StaticResource HeaderBackgroundBrush}" />
<Border SnapsToDevicePixels="True" Margin="1,1,1,0"
BorderBrush="White" BorderThickness="0,1,0,0" />
<Polygon x:Name="Arrow"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Margin="8,8,3,3"
Opacity="0.15"
Fill="Black"
Stretch="Uniform"
Points="0,10 10,10 10,0" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Fill"
Value="{StaticResource HeaderHighlightedBackgoundBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Border" Property="Fill"
Value="{StaticResource HeaderPressedBackgroundBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Arrow" Property="Visibility" Value="Collapsed" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- DataGrid Style -->
<Style x:Key="{x:Type DataGrid}" TargetType="{x:Type DataGrid}">
<Setter Property="Background" Value="{StaticResource DefaultControlBackgroundBrush}"/>
<Setter Property="Foreground" Value="{StaticResource DefaultControlForegroundBrush}"/>
<!-- Remove border around the grid -->
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="HorizontalGridLinesBrush" Value="{StaticResource GridLineColorBrush}" />
<Setter Property="VerticalGridLinesBrush" Value="{StaticResource GridLineColorBrush}" />
<Setter Property="AlternatingRowBackground" Value="{StaticResource AlternateRowBackgroundBrush}" />
<Setter Property="ColumnHeaderStyle" Value="{StaticResource DataGridColumnHeaderStyle}"/>
<!-- This is needed to force DG to have a non-default value. Otherwise the DGR.DetailsVisibility cannot have a value of VisibleWhenSelected by default. -->
<Setter Property="RowDetailsVisibilityMode" Value="VisibleWhenSelected" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<!-- Turn off row headers by default. -->
<Setter Property="HeadersVisibility" Value="Column" />
<Setter Property="GridLinesVisibility" Value="Horizontal" />
<Setter Property="ColumnHeaderHeight" Value="32" />
<Setter Property="RowHeight" Value="32" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGrid}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True"
Padding="{TemplateBinding Padding}">
<ScrollViewer Focusable="false" Name="DG_ScrollViewer">
<ScrollViewer.Template>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!--Left Column Header Corner -->
<Button
Command="{x:Static DataGrid.SelectAllCommand}"
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=CellsPanelHorizontalOffset}"
Focusable="false"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.All}}"
Template="{StaticResource SelectAllButtonTemplate}"/>
<!--Column Headers-->
<DataGridColumnHeadersPresenter
Grid.Column="1"
Name="PART_ColumnHeadersPresenter"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Column}}"/>
<!--DataGrid content-->
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Grid.Row="1" Grid.ColumnSpan="2" CanContentScroll="{TemplateBinding CanContentScroll}" />
<ScrollBar
Grid.Row="0" Grid.RowSpan="2" Grid.Column="2" Name="PART_VerticalScrollBar"
Orientation="Vertical"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{Binding Path=VerticalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
<Grid Grid.Row="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=NonFrozenColumnsViewportHorizontalOffset}"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollBar
Grid.Column="1"
Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{Binding Path=HorizontalOffset, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
</Grid>
</Grid>
</ControlTemplate>
</ScrollViewer.Template>
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
【问题讨论】:
-
你知道默认的 .ToString() 给出了类名,对吧?因此,也许您缺少 Path=... 或其他内容。
-
我已更新我的问题以澄清您的评论。
-
嗨,naresh,您能否也分享一下编辑后的模板。 1) 通过实现,DataGridColumnHeaderPresenter 是从 Border 派生的,因为它是一个内容控件,您可以将任何元素分配为子元素。在这种情况下,它是一个 TextBlock。 2) 那 - 我们必须全面检查模板。那么,只有我们才能得出结论。 3) 是的,DataGridTextColumn 的 Header 属性。您已经分配的。 msdn.microsoft.com/en-us/library/…
-
您好 Avatar,我已将整个模板添加到问题中。如果您发现异常,请查看并告诉我。仅供参考,我的示例中的列显示正确。例如,上例中的“创建时间”列显示正确。只是这些列下面有一个文本块,由于我只有几列,所以完全分类的类名的尾部显示出来(因为它大于实际列的总宽度)!