Подтвердить что ты не робот

Выровнять нижние части текста в элементах управления

Следующий фрагмент:

<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>

Отдает следующее:
alt text

Есть ли способ, который я могу установить в стилях Labels, чтобы их нижние части текста были выровнены?
У меня тоже вопрос с TextBlocks.

ПРИМЕЧАНИЕ. Поскольку я некоторое время боролся с этой проблемой, отправьте только те сертификаты, которые вы знаете, что работаете. Я уже пробовал: VerticalAlignment, VerticalContentAlignment, Padding, Margin. Есть ли что-то еще, о чем я не знаю?

Я прочитал этот пост, но он не говорит о сценарии разного размера шрифта.

ОБНОВЛЕНИЕ. Проблема заключается в том, что даже для параметра "Заполнение" установлено значение 0, в пределах области ContentPresenter по-прежнему существует неопределенное пространство вокруг шрифта. это пространство зависит от размера шрифта. Если бы я мог контролировать это пространство, я был бы в лучшей ситуации.

Спасибо

4b9b3361

Ответ 1

Нет решения XAML, вам нужно использовать код. Кроме того, даже с кодовым отставанием нет общего решения для этого, потому что, если ваш текст многострочный? Какую базовую линию следует использовать в этом случае? Или что, если в вашем шаблоне есть несколько текстовых элементов? Например, заголовок и контент, или более, какой исходный уровень?

Короче говоря, лучше всего выровнять текст вручную, используя верхние/нижние поля.

Если вы хотите сделать предположение, что у вас есть один текстовый элемент, вы можете определить расстояние между пикселями базовой линии от вершины элемента, создав экземпляр объекта FormattedText со всеми теми же свойствами существующий текстовый элемент. Объект FormattedText имеет свойство double Baseline, которое содержит это значение. Обратите внимание, что вам все равно придется вручную вводить маржу, потому что элемент может не совпадать точно с верхней или нижней частью контейнера.

См. сообщение на форуме MSDN: Исходная строка текстового поля

Здесь метод, который я написал, извлекает это значение. Он использует отражение для получения соответствующих свойств, потому что они не являются общими для какого-либо одного базового класса (они определяются отдельно на Control, TextBlock, Page, TextElement и, возможно, на других).

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;
}

EDIT: Shimmy, в ответ на ваш комментарий, я не верю, что вы действительно пробовали это решение, потому что оно работает. Вот пример:

Example Baseline Alignment

Здесь 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>

И вот здесь код, достигающий этого

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);

Ответ 2

Другое довольно простое решение:

1) Используйте элементы управления TextBlock вместо ярлыков. Причина в том, что TextBlock легче, чем Label - см. 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>

Ответ 3

Мне очень нравятся творческие решения, которые представлены здесь, но я думаю, что в конечном итоге (каламбур) мы должны использовать это:

<TextBlock>
   <Run FontSize="20">What</Run>
   <Run FontSize="36">ever</Run>
   <Run FontSize="12" FontWeight="Bold">FontSize</Run>
</TextBlock>

Единственное, что отсутствует в элементе Run, это привязка свойства Text, но может быть добавлена ​​рано или поздно.

A Run не будет исправлять выравнивание меток и их текстовых полей, но для многих простых ситуаций Run будет очень приятным.

Ответ 4

<TextBlock>
<InlineUIContainer BaselineAlignment="Baseline"><TextBlock>Small</TextBlock></InlineUIContainer>
<InlineUIContainer BaselineAlignment="Baseline"><TextBlock FontSize="50">Big</TextBlock></InlineUIContainer>
</TextBlock>

Это должно хорошо работать. Эксперимент с базовым/нижним/центральным/верхним.

Ответ 5

Конструктор XAML поддерживает выравнивание элементов управления TextBlock по базовой линии во время разработки:

enter image description here

Это назначает фиксированные поля вашим элементам управления. Пока размер шрифта не изменяется во время выполнения, выравнивание будет сохранено.

Ответ 6

На самом деле я нашел простой ответ на основе Aviad.

Я создал конвертер, который содержит функцию Aviad, которая принимает сам элемент и возвращает расчетную толщину.

Затем я установил

<Style TargetType="TextBlock">
    <Setter Property="Margin" 
        Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource converters:TextAlignmentMarginConverter}}" />
</Style>

Недостаток заключается в том, что он явно занимает исходное свойство Margin, поскольку TextBlock не имеет шаблона, поэтому мы не можем его установить через TemplateBinding.