TextBlock文本不在DataGridCell中垂直居中 [英] TextBlock text not vertically centering within DataGridCell
问题描述
我正在C#中创建一个 DataGrid
(来自代码隐藏/非XAML),但是无论我如何尝试,我都无法获得该文本在数据单元格中垂直居中:
I'm creating a DataGrid
in C# (from code-behind/not XAML), but no matter what I try, I can't get the text to be vertically center in the data cells:
我从以下开始:
var CellStyle = new Style(typeof(DataGridCell)) {
Setters = {
new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Center)
}
};
正确定位单元格并将文本水平居中(根据上面的屏幕截图)。
Which correctly targets the cell and horizontally centres the text (per the screenshot above).
尝试垂直放置文本居中,我知道 TextBlock
不支持垂直内容对齐,仅支持其内部的垂直对齐
Trying to vertically center the text, I know that a TextBlock
doesn't support vertical content alignment, only its own vertical alignment within a parent element.
每个问题( WPF TextBlock中的文本垂直对齐)我尝试使用 Padding
伪造它:
Per this question (Text vertical alignment in WPF TextBlock) I tried to fake it using Padding
:
var CellStyle = new Style(typeof(DataGridCell)) {
Setters = {
new Setter(TextBlock.PaddingProperty, new Thickness(5)),
new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Center)
}
};
这没什么区别。然后我尝试了以下方法:
This made no difference. Then I tried this:
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)
}
};
其结果是:
添加新的Setter(DataGridCell.HeightProperty ,50d),
会显示在屏幕快照1中。
Adding new Setter(DataGridCell.HeightProperty, 50d),
results in screenshot #1.
如何在数据单元格中垂直放置文本?
How can I vertically center the text in my data cells?
推荐答案
使用Blend for Visual Studio,我们为 DataGridCell
使用这种样式:
Using Blend for Visual Studio, we have this style for the 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>
应该具有以下代码:
So looks like there is not any default support for changing the alignments here. Normally the <ContentPresenter>
should have code like this:
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
然后我们可以更改 VerticalContentAlignment
和 HorizontalContentAlignment
类似于 DataGridCell
的样式,以更改对齐方式。
Then we can change the VerticalContentAlignment
and HorizontalContentAlignment
in the style of the DataGridCell
to change the alignments.
这意味着如果使用XAML代码,则只需附加以上代码即可解决您的解决方案。但是,如果您想在后面使用代码,则它的使用时间当然会更长且更复杂。
That means if using XAML code, your solution can be solved by just appending the above code. But if you want to use code behind, it's of course much longer and more complicated.
在这里,我向您介绍两种解决方案。首先通过为 ControlTemplate
构建VisualTree并将该模板设置为 DataGridCell的
: Template
属性
Here I introduce to you 2 solutions. First by building the VisualTree for the ControlTemplate
and set that template for the Template
property of DataGridCell
:
//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
将解析该字符串并给出样式
:
The second solution is by using XamlReader
to parse the XAML code directly, that means we need the exact XAML code as given before saved in a string and XamlReader
will parse that string giving out an instance of 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代码设计的,因此使用后面的代码当然并不简单,而且通常很冗长。
You can see that both solutions are fairly long but they are actually what you should do using code behind. That means we should always use XAML code as much as possible. Many features in WPF are designed mainly for XAML code, so using code behind is of course not straightforward and usually verbose.
注意:我在开始时发布的code> XAML 代码不是 DataGridCell
的完整默认样式,它还有更多的触发器
。抱歉,这意味着代码可能更长,这是完整的默认XAML代码:
NOTE: The XAML
code I posted at the beginning is not the full default style for DataGridCell
, it has some more Triggers
. That means the code may be much longer, sorry, here is the full default XAML code:
<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
仍然有效:
However I've just tested it, looks like the default style is always applied to the DataGridCell
, it's just overridden by the Setter
you added (which set the same properties). Here is the testing code, the Trigger
still works:
//change the highlight selected brush to Red (default by blue).
yourDataGrid.Resources.Add(SystemColors.HighlightBrushKey, Brushes.Red);
这篇关于TextBlock文本不在DataGridCell中垂直居中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!