TextBlock文本不在DataGridCell中垂直居中 [英] TextBlock text not vertically centering within DataGridCell

查看:98
本文介绍了TextBlock文本不在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 Horizo​​ntalContentAlignment 类似于 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆