对齐控件中的文本底部

Shi*_*mmy 17 wpf layout textblock

以下片段:

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <StackPanel Orientation="Horizontal"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center">            
            <Label Content="Name:"/>
            <Label Content="Itzhak Perlman" FontSize="44"/>
        </StackPanel>
    </Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

呈现以下内容:
替代文字

有没有什么方法可以设置标签的样式,以便他们的文本底部应该对齐?
我对TextBlocks也有同样的问题.

注意:由于我一直在努力解决这个问题,请发布您知道可行的某些答案.
我已经尝试过:VerticalAlignment,VerticalContentAlignment,Padding,Margin.还有什么我不知道的吗?

我已经阅读过这篇文章,但它没有谈到不同字体大小的情况.

更新:问题是,即使Padding设置为0,在ContentPresenter区域内的字体周围仍然存在不确定的空间.这个空间因字体大小而异.如果我可以控制这个空间,我会处于更好的状态.

谢谢

小智 26

另一个相当简单的解

1)使用TextBlock控件而不是标签.原因是,TextBlock的重量更轻比标签-看http://joshsmithonwpf.wordpress.com/2007/07/04/differences-between-label-and-textblock/

2)使用LineHeight和LineStackingStrategy = BlockLineHeight作为TextBlock样式.这将使两者在基线处轻松对齐.

<StackPanel Orientation="Horizontal"
            VerticalAlignment="Center"
            HorizontalAlignment="Center">
    <StackPanel.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="LineHeight" Value="44pt"/>
            <Setter Property="LineStackingStrategy" Value="BlockLineHeight"/>
        </Style>
    </StackPanel.Resources>            
    <TextBlock Text="Name:"/>
    <TextBlock Text="Itzhak Perlman" FontSize="44"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)


Avi*_* P. 6

There is no XAML only solution, you have to use code behind. Also, even with code-behind, there's no general solution for this, because what if your text is multi-line? Which baseline should be used in that case? Or what if there are multiple text elements in your template? Such as a header and a content, or more, which baseline then?

In short, your best bet is to align the text manually using top/bottom margins.

If you're willing to make the assumption that you have a single text element, you can figure out the pixel distance of the baseline from the top of the element by instantiating a FormattedText object with all the same properties of the existing text element. The FormattedText object has a double Baseline property which holds that value. Note that you still would have to manually enter a margin, because the element might not sit exactly against the top or bottom of its container.

See this MSDN forum post: Textbox Baseline

Here's a method I wrote that extracts that value. It uses reflection to get the relevant properties because they are not common to any single base class (they are defined separately on Control, TextBlock, Page, TextElement and maybe others).

public double CalculateBaseline(object textObject)
{
    double r = double.NaN;
    if (textObject == null) return r;

    Type t = textObject.GetType();
    BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public;

    var fontSizeFI = t.GetProperty("FontSize", bindingFlags);
    if (fontSizeFI == null) return r;
    var fontFamilyFI = t.GetProperty("FontFamily", bindingFlags);
    var fontStyleFI = t.GetProperty("FontStyle", bindingFlags);
    var fontWeightFI = t.GetProperty("FontWeight", bindingFlags);
    var fontStretchFI = t.GetProperty("FontStretch", bindingFlags);

    var fontSize = (double)fontSizeFI.GetValue(textObject, null);
    var fontFamily = (FontFamily)fontFamilyFI.GetValue(textObject, null);
    var fontStyle = (FontStyle)fontStyleFI.GetValue(textObject, null);
    var fontWeight = (FontWeight)fontWeightFI.GetValue(textObject, null);
    var fontStretch = (FontStretch)fontStretchFI.GetValue(textObject, null);

    var typeFace = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch);

    var formattedText = new FormattedText(
        "W", 
        CultureInfo.CurrentCulture, 
        FlowDirection.LeftToRight, 
        typeFace, 
        fontSize, 
        Brushes.Black);

    r = formattedText.Baseline;

    return r;
}
Run Code Online (Sandbox Code Playgroud)

编辑:Shimmy,回应你的评论,我不相信你真的尝试过这个解决方案,因为它有效.这是一个例子:

示例基线对齐

这是XAML:

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="Margin" Value="0,40,0,0"/>
        </Style>
    </StackPanel.Resources>
    <StackPanel Orientation="Horizontal">
        <TextBlock Name="tb1" Text="Lorem " FontSize="10"/>
        <TextBlock Name="tbref" Text="ipsum"/>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock Name="tb2" Text="dolor "  FontSize="20"/>
        <TextBlock Text="sit"/>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock Name="tb3" Text="amet "  FontSize="30"/>
        <TextBlock Text="consectetuer"/>
    </StackPanel>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)

这是实现这一目标的背后代码

double baseRef = CalculateBaseline(tbref);
double base1 = CalculateBaseline(tb1) - baseRef;
double base2 = CalculateBaseline(tb2) - baseRef;
double base3 = CalculateBaseline(tb3) - baseRef;
tb1.Margin = new Thickness(0, 40 - base1, 0, 0);
tb2.Margin = new Thickness(0, 40 - base2, 0, 0);
tb3.Margin = new Thickness(0, 40 - base3, 0, 0);
Run Code Online (Sandbox Code Playgroud)


小智 6

我真的很喜欢这里展示的创意解决方案,但我认为从长远来看(双关语)我们应该使用这个:

<TextBlock>
   <Run FontSize="20">What</Run>
   <Run FontSize="36">ever</Run>
   <Run FontSize="12" FontWeight="Bold">FontSize</Run>
</TextBlock>
Run Code Online (Sandbox Code Playgroud)

Run元素中唯一缺少的是Text属性的数据绑定,但可能迟早会添加.

A Run不会修复标签及其文本框的对齐方式,但对于许多简单的情况,Run会做得非常好.