【问题标题】:Why is WPF DataGrid showing a class name in the header?为什么 WPF DataGrid 在标题中显示类名?
【发布时间】: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)

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

  1. 为什么边框需要 TextBlock?
  2. 为什么用 DataContext 的类名初始化 TextBlock?
  3. 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,我已将整个模板添加到问题中。如果您发现异常,请查看并告诉我。仅供参考,我的示例中的列显示正确。例如,上例中的“创建时间”列显示正确。只是这些列下面有一个文本块,由于我只有几列,所以完全分类的类名的尾部显示出来(因为它大于实际列的总宽度)!

标签: wpf datagrid


【解决方案1】:

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>

【讨论】:

  • 就是这样!我不知道我是从哪里找到我的原始模板的,但是用 ContentPresenter 替换 TextBlock 就可以了。非常感谢!
猜你喜欢
  • 2019-03-26
  • 1970-01-01
  • 2010-10-14
  • 2014-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多