【问题标题】:TextBlock text not vertically centering within DataGridCellTextBlock 文本不在 DataGridCell 内垂直居中
【发布时间】:2014-10-19 22:36:36
【问题描述】:

我正在 C# 中创建一个 DataGrid(来自代码隐藏/不是 XAML),但无论我尝试什么,我都无法让文本在数据单元格中垂直居中:

我一开始是:

var CellStyle = new Style(typeof(DataGridCell)) {
    Setters = {
        new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Center)
    }
};

正确定位单元格并将文本水平居中(根据上面的屏幕截图)。

尝试将文本垂直居中,我知道 TextBlock 不支持垂直内容对齐,只支持它自己在父元素中的垂直对齐。

根据这个问题 (Text vertical alignment in WPF TextBlock) 我尝试使用 Padding 伪造它:

var CellStyle = new Style(typeof(DataGridCell)) {
    Setters = {
        new Setter(TextBlock.PaddingProperty, new Thickness(5)),
        new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Center)
    }
};

这没什么区别。然后我尝试了这个:

var CellStyle = new Style(typeof(DataGridCell)) {
    Setters = {
        new Setter(DataGridCell.VerticalContentAlignmentProperty, VerticalAlignment.Center),
        new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Center),
        new Setter(TextBlock.VerticalAlignmentProperty, VerticalAlignment.Center)
    }
};

导致:

添加 new Setter(DataGridCell.HeightProperty, 50d), 会生成屏幕截图 #1。

如何将数据单元格中的文本垂直居中?

【问题讨论】:

  • 您是在使用 CellTemplate,而不是仅仅为您的单元格样式填充 TextColumns 或其他一些模板吗?我假设是这样,因为这看起来像是一种非常非默认的样式。
  • @ChrisW。不,没有模板!这是完整的源代码(一周内自毁):pastebin.com/Sc5tWnDH - Screen 类是最小的并且不包含任何样式。
  • 尝试在 VerticalAlignment 上拉伸而不是居中

标签: c# wpf xaml datagrid vertical-alignment


【解决方案1】:

使用 Blend for Visual Studio,我们为 DataGridCell 提供了这种样式:

<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                <Border BorderBrush="{TemplateBinding BorderBrush}" 
                        BorderThickness="{TemplateBinding BorderThickness}" 
                        Background="{TemplateBinding Background}" 
                        SnapsToDevicePixels="True"                          
                >
                    <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
</Setter>

所以看起来这里没有任何默认支持更改对齐方式。通常&lt;ContentPresenter&gt; 应该有这样的代码:

<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>

然后我们可以改变DataGridCell的样式中的VerticalContentAlignmentHorizontalContentAlignment来改变对齐方式。

这意味着如果使用 XAML 代码,只需附加上述代码即可解决您的解决方案。但是如果你想在后面使用代码,当然要更长更复杂。

这里我给大家介绍2个解决方案。首先为ControlTemplate 构建VisualTree 并为DataGridCellTemplate 属性设置该模板:

//root visual of the ControlTemplate for DataGridCell is a Border
var border = new FrameworkElementFactory(typeof(Border));
border.SetBinding(Border.BorderBrushProperty, new Binding("BorderBrush") { 
        RelativeSource = RelativeSource.TemplatedParent
});
border.SetBinding(Border.BackgroundProperty, new Binding("Background") {RelativeSource = RelativeSource.TemplatedParent });
border.SetBinding(Border.BorderThicknessProperty, new Binding("BorderThickness") {RelativeSource = RelativeSource.TemplatedParent });
border.SetValue(SnapsToDevicePixelsProperty, true);
//the only child visual of the border is the ContentPresenter
var contentPresenter = new FrameworkElementFactory(typeof(ContentPresenter));
contentPresenter.SetBinding(SnapsToDevicePixelsProperty, new Binding("SnapsToDevicePixelsProperty") {RelativeSource=RelativeSource.TemplatedParent });
contentPresenter.SetBinding(VerticalAlignmentProperty, new Binding("VerticalContentAlignment") { RelativeSource = RelativeSource.TemplatedParent });
contentPresenter.SetBinding(HorizontalAlignmentProperty, new Binding("HorizontalContentAlignment") {RelativeSource = RelativeSource.TemplatedParent });
//add the child visual to the root visual
border.AppendChild(contentPresenter);

//here is the instance of ControlTemplate for DataGridCell
var template = new ControlTemplate(typeof(DataGridCell));
template.VisualTree = border;
//define the style
var style = new Style(typeof(DataGridCell));
style.Setters.Add(new Setter(TemplateProperty, template));
style.Setters.Add(new Setter(VerticalContentAlignmentProperty, 
                             VerticalAlignment.Center));
style.Setters.Add(new Setter(HorizontalContentAlignmentProperty, 
                             HorizontalAlignment.Center));
yourDataGrid.CellStyle = style;

第二种解决方案是使用XamlReader 直接解析XAML 代码,这意味着我们需要在字符串中保存之前给出的确切XAML 代码,XamlReader 将解析该字符串并给出Style 的实例:

var xaml = "<Style TargetType=\"{x:Type DataGridCell}\"><Setter Property=\"VerticalContentAlignment\" Value=\"Center\"/>" +
           "<Setter Property=\"HorizontalContentAlignment\" Value=\"Center\"/>" +
           "<Setter Property=\"Template\">" +
           "<Setter.Value><ControlTemplate TargetType=\"DataGridCell\">" +
           "<Border BorderBrush=\"{TemplateBinding BorderBrush}\" BorderThickness=\"{TemplateBinding BorderThickness}\" Background=\"{TemplateBinding Background}\" SnapsToDevicePixels=\"True\">" +
           "<ContentPresenter SnapsToDevicePixels=\"{TemplateBinding SnapsToDevicePixels}\" VerticalAlignment=\"{TemplateBinding VerticalContentAlignment}\" HorizontalAlignment=\"{TemplateBinding HorizontalContentAlignment}\"/>" +
           "</Border></ControlTemplate></Setter.Value></Setter></Style>";

var parserContext = new System.Windows.Markup.ParserContext();          
parserContext.XmlnsDictionary
             .Add("","http://schemas.microsoft.com/winfx/2006/xaml/presentation");
parserContext.XmlnsDictionary
             .Add("x","http://schemas.microsoft.com/winfx/2006/xaml");            
yourDataGrid.CellStyle = (Style)System.Windows.Markup.XamlReader.Parse(xaml,parserContext); 

您可以看到这两种解决方案都相当长,但它们实际上是您应该使用后面的代码执行的操作。这意味着我们应该始终尽可能多地使用 XAML 代码。 WPF 中的许多功能主要是为 XAML 代码设计的,因此使用后面的代码当然并不简单,而且通常很冗长。

注意:我在开头发布的XAML 代码不是DataGridCell 的完整默认样式,它还有更多Triggers。这意味着代码可能会更长,抱歉,这是完整的默认 XAML 代码:

<Style TargetType="{x:Type DataGridCell}">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True"                            
                >
                    <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
            <Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
        </Trigger>
        <Trigger Property="IsKeyboardFocusWithin" Value="True">
            <Setter Property="BorderBrush" Value="{DynamicResource {x:Static DataGrid.FocusBorderBrushKey}}"/>
        </Trigger>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsSelected" Value="true"/>
                <Condition Property="Selector.IsSelectionActive" Value="false"/>
            </MultiTrigger.Conditions>
            <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
            <Setter Property="BorderBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
        </MultiTrigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
        </Trigger>
    </Style.Triggers>
</Style>

但是我刚刚测试过,看起来默认样式始终应用于DataGridCell,它只是被您添加的Setter 覆盖(设置相同的属性)。这是测试代码,Trigger 仍然有效:

//change the highlight selected brush to Red (default by blue).
yourDataGrid.Resources.Add(SystemColors.HighlightBrushKey, Brushes.Red);

【讨论】:

  • +1 只是为了将其指向 XAML 而不是后面的代码。谢谢你:)
  • 感谢您的全面回答!我使用了XamlReader.Parse() 解决方案,因为我已经有一个ParserContext 用于我可以重复使用的另一种样式。它有效,非常感谢! @ChrisW。我已经在 XAML 中有这个,并且必须将它转换为 C# 以便在一些动态内容创建中使用。
  • 我设法将其缩短为(使用原始 XAML):var xaml = "&lt;Style x:Key=\"DataGridCellStyle\" TargetType=\"DataGridCell\"&gt;&lt;Setter Property=\"Template\"&gt;&lt;Setter.Value&gt;&lt;ControlTemplate TargetType=\"{x:Type DataGridCell}\"&gt;&lt;ContentPresenter HorizontalAlignment=\"Center\" VerticalAlignment=\"Center\"/&gt;&lt;/ControlTemplate&gt;&lt;/Setter.Value&gt;&lt;/Setter&gt;&lt;/Style&gt;";
  • @DannyBeckett 是的,我打算将TemplateBinding 用于VerticalAlignmentHorizontalAlignment。然后我们可以在一段时间后将VerticalContentAignmentHorizontalContentAlignment 更改为我们想要的DataGridCell 样式。
【解决方案2】:

我的回答只是总结了King King,以防它对某人有所帮助。在 XAML 中:

DataGrid where 中使用属性CellStyle="{StaticResource CustomCell}"

<Style x:Key="CustomCell" TargetType="{x:Type DataGridCell}">
    <Setter Property="VerticalContentAlignment" Value="Center" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

【讨论】:

    猜你喜欢
    • 2023-03-05
    • 2018-04-26
    • 2011-11-28
    • 2013-10-15
    • 2016-07-29
    • 2014-03-23
    • 1970-01-01
    • 2015-09-16
    相关资源
    最近更新 更多