TextBlock 文本不在 DataGridCell 内垂直居中
Posted
技术标签:
【中文标题】TextBlock 文本不在 DataGridCell 内垂直居中【英文标题】:TextBlock text not vertically centering within 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 上拉伸而不是居中
【参考方案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>
所以看起来这里没有任何默认支持更改对齐方式。通常<ContentPresenter>
应该有这样的代码:
<ContentPresenter SnapsToDevicePixels="TemplateBinding SnapsToDevicePixels"
VerticalAlignment="TemplateBinding VerticalContentAlignment"
HorizontalAlignment="TemplateBinding HorizontalContentAlignment"/>
然后我们可以改变DataGridCell
的样式中的VerticalContentAlignment
和HorizontalContentAlignment
来改变对齐方式。
这意味着如果使用 XAML 代码,只需附加上述代码即可解决您的解决方案。但是如果你想在后面使用代码,当然要更长更复杂。
这里我给大家介绍2个解决方案。首先为ControlTemplate
构建VisualTree 并为DataGridCell
的Template
属性设置该模板:
//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 = "<Style x:Key=\"DataGridCellStyle\" TargetType=\"DataGridCell\"><Setter Property=\"Template\"><Setter.Value><ControlTemplate TargetType=\"x:Type DataGridCell\"><ContentPresenter HorizontalAlignment=\"Center\" VerticalAlignment=\"Center\"/></ControlTemplate></Setter.Value></Setter></Style>";
@DannyBeckett 是的,我打算将TemplateBinding
用于VerticalAlignment
和HorizontalAlignment
。然后我们可以在一段时间后将VerticalContentAignment
和HorizontalContentAlignment
更改为我们想要的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>
【讨论】:
以上是关于TextBlock 文本不在 DataGridCell 内垂直居中的主要内容,如果未能解决你的问题,请参考以下文章