为什么WPF DataGrid在标题中显示类名?

时间:2010-08-17 13:56:40

标签: wpf datagrid

我通过覆盖其控件模板为我的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)

这个文本块包含类名!所以问题是

  1. 边框为什么需要TextBlock?
  2. 为什么TextBlock使用DataContext的类名初始化?
  3. DataGrid级别是否存在控制此TextBlock的内容的属性?
  4. P.S。要回答下面的评论,我正在为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>
    

1 个答案:

答案 0 :(得分:7)

DataGridColumnHeadersPresenter的默认模板如下所示:

<ControlTemplate TargetType="{x:Type DataGridColumnHeadersPresenter}">
    <Grid>
        <DataGridColumnHeader IsHitTestVisible="False"
            Name="PART_FillerColumnHeader"/>
        <ItemsPresenter />
    </Grid>
</ControlTemplate>

ItemsPresenter会为每列创建一个DataGridColumnHeader,但该模板还包含一个DataGridColumnHeader,它在整个网格中展开以充当背景。它没有内容,所以它通常只是在适当的主题中绘制边框。

但是,您的DataGridColumnHeader模板包含TextBlock而不是ContentPresenter,因此它会将DataContext呈现为字符串,无论它是否也是内容。尝试使用ContentPresenter代替TextBlock

<Border BorderBrush="{StaticResource HeaderInnerBorderBrush}" 
        BorderThickness="0,1,0,0">
    <ContentPresenter
        Margin="7,0,7,0"
        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
        VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" />
</Border>