简体   繁体   English

TextBlock文本不在DataGridCell中垂直居中

[英]TextBlock text not vertically centering within DataGridCell

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

]

I started off with: 我开始时:

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). 哪个正确地定位单元格并使文本水平居中(根据上面的屏幕截图)。

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. 尝试垂直居中文本,我知道TextBlock不支持垂直内容对齐,只支持父元素中自己的垂直对齐。

Per this question ( Text vertical alignment in WPF TextBlock ) I tried to fake it using Padding : 根据这个问题( WPF TextBlock中的文本垂直对齐 )我试图使用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)
    }
};

Which resulted in: 结果导致:

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

How can I vertically center the text in my data cells? 如何在数据单元格中垂直居中显示文本?

Using Blend for Visual Studio, we have this style for the DataGridCell : 使用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>

So looks like there is not any default support for changing the alignments here. 所以看起来没有任何默认支持来更改对齐方式。 Normally the <ContentPresenter> should have code like this: 通常, <ContentPresenter>应该具有以下代码:

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

Then we can change the VerticalContentAlignment and HorizontalContentAlignment in the style of the DataGridCell to change the alignments. 然后我们可以更改DataGridCell样式中的VerticalContentAlignmentHorizontalContentAlignment来更改对齐。

That means if using XAML code, your solution can be solved by just appending the above code. 这意味着如果使用XAML代码,只需附加上面的代码即可解决您的解决方案。 But if you want to use code behind, it's of course much longer and more complicated. 但是如果你想使用代码,它当然会更长,更复杂。

Here I introduce to you 2 solutions. 在这里,我向您介绍2个解决方案。 First by building the VisualTree for the ControlTemplate and set that template for the Template property of DataGridCell : 首先,为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;

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 : 第二种解决方案是使用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); 

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. 这意味着我们应该尽可能多地使用XAML代码。 Many features in WPF are designed mainly for XAML code, so using code behind is of course not straightforward and usually verbose. WPF中的许多功能主要是为XAML代码设计的,因此使用后面的代码当然不是直截了当且通常很冗长。

NOTE : The XAML code I posted at the beginning is not the full default style for DataGridCell , it has some more Triggers . 注意 :我在开头发布的XAML代码不是DataGridCell的完整默认样式,它有一些Triggers That means the code may be much longer, sorry, here is the full default XAML code: 这意味着代码可能会更长,抱歉,这是完整的默认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>

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). 但是我刚试过它,看起来默认样式总是应用于DataGridCell ,它只是被你添加的Setter覆盖(设置了相同的属性)。 Here is the testing code, the Trigger still works: 这是测试代码, Trigger仍然有效:

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

My answer just summarizes King King 's, in case it helps someone. 我的回答只是总结了King King的,以防它帮助某人。 In XAML: 在XAML中:

Use the property CellStyle="{StaticResource CustomCell}" in your DataGrid where DataGrid中使用属性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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM