TextBlock с текстом по левому краю, а остальной текст Как правильно выровнены

Я хочу иметь textblock, который содержит текст, как показано ниже:

My associated textbox is                :

текст выровнен по левому краю и двоеточие выровнено по правому краю.

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

3 ответов


TextBlock по своей сути противоречит концепции выровненных детей, но, конечно, есть некоторые возможные хаки способы работы:

  1. заполнить пробелы, чтобы создать видимость трассы.
  2. использовать InlineUIContainer чтобы добавить фактические элементы пользовательского интерфейса (которые вы can align) внутри текстового блока.

я приведу пример каждого, создав ExtendedTextBlock управления, с LeftAlignedText и RightAlignedText свойства. Использование выглядит следующим образом:

<my:ExtendedTextBlock RightAlignedText=":" LeftAlignedText="My associated textbox is" />

1) отступы с пробелами.

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

public class ExtendedTextBlock : TextBlock
{
    public string RightAlignedText
    {
        get { return (string)GetValue(RightAlignedTextProperty); }
        set { SetValue(RightAlignedTextProperty, value); }
    }
    public static readonly DependencyProperty RightAlignedTextProperty =
        DependencyProperty.Register("RightAlignedText", typeof(string), typeof(ExtendedTextBlock), new PropertyMetadata(SetText));

    public string LeftAlignedText
    {
        get { return (string)GetValue(LeftAlignedTextProperty); }
        set { SetValue(LeftAlignedTextProperty, value); }
    }
    public static readonly DependencyProperty LeftAlignedTextProperty =
        DependencyProperty.Register("LeftAlignedText", typeof(string), typeof(ExtendedTextBlock), new PropertyMetadata(SetText));

    public static void SetText(object sender, DependencyPropertyChangedEventArgs args)
    {
        SetText((ExtendedTextBlock)sender);
    }

    public static void SetText(ExtendedTextBlock owner)
    {
        if (owner.ActualWidth == 0)
            return;

        // helper function to get the width of a text string
        Func<string, double> getTextWidth = text =>
        {
            var formattedText = new FormattedText(text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight,
                new Typeface(owner.FontFamily, owner.FontStyle, owner.FontWeight, owner.FontStretch),
                owner.FontSize,
                Brushes.Black);
            return formattedText.Width;
        };

        // calculate the space needed to fill in
        double spaceNeeded = owner.ActualWidth - getTextWidth(owner.LeftAlignedText ?? "") - getTextWidth(owner.RightAlignedText ?? "");

        // get the width of an empty space (have to cheat a bit since the width of an empty space returns zero)
        double spaceWidth = getTextWidth(" .") - getTextWidth(".");
        int spaces = (int)Math.Round(spaceNeeded / spaceWidth);

        owner.Text = owner.LeftAlignedText + new string(Enumerable.Repeat(' ', spaces).ToArray()) + owner.RightAlignedText;
    }

    public ExtendedTextBlock()
    {
        SizeChanged += (sender, args) => SetText(this);
    }
}

2) используя InlineUIContainer добавить выровненный текст

в идея здесь состоит в том, чтобы добавить панель, внутри TextBlock, который будет отвечать за согласование каждой текстовой строки. Это основная идея:

<TextBlock>
    <InlineUIContainer>
        <Grid Width="{Binding RelativeSource={RelativeSource AncestorType=TextBlock},Path=ActualWidth}">
            <TextBlock Text="Hello" />
            <TextBlock Text="World" TextAlignment="Right" />
        </Grid>
    </InlineUIContainer>
</TextBlock>

таким образом, эта версия элемента управления повторно создает выше, но скрывает реализацию. Он добавляет InlineUIContainer управление базой TextBlock, и сохраняет ссылку на "левый" и "правый"TextBlocks, устанавливая их текст по мере необходимости.

public class ExtendedTextBlock2 : TextBlock
{
    private TextBlock _left, _right;

    public string RightAlignedText
    {
        get { return (string)GetValue(RightAlignedTextProperty); }
        set { SetValue(RightAlignedTextProperty, value); }
    }
    public static readonly DependencyProperty RightAlignedTextProperty =
        DependencyProperty.Register("RightAlignedText", typeof(string), typeof(ExtendedTextBlock2), new PropertyMetadata(SetText));

    public string LeftAlignedText
    {
        get { return (string)GetValue(LeftAlignedTextProperty); }
        set { SetValue(LeftAlignedTextProperty, value); }
    }
    public static readonly DependencyProperty LeftAlignedTextProperty =
        DependencyProperty.Register("LeftAlignedText", typeof(string), typeof(ExtendedTextBlock2), new PropertyMetadata(SetText));

            public static void SetText(object sender, DependencyPropertyChangedEventArgs args)
    {
        ((ExtendedTextBlock2)sender).SetText();
    }

    public void SetText()
    {
        if (_left == null || _right == null)
            return;
        _left.Text = LeftAlignedText;
        _right.Text = RightAlignedText;
    }

    public ExtendedTextBlock2()
    {
        Loaded += ExtendedTextBlock2_Loaded;
    }

    void ExtendedTextBlock2_Loaded(object sender, RoutedEventArgs e)
    {
        Inlines.Clear();
        var child = new InlineUIContainer();
        var container = new Grid();
        var widthBinding = new Binding { Source = this, Path = new PropertyPath(TextBlock.ActualWidthProperty) };
        container.SetBinding(Grid.WidthProperty, widthBinding);
        child.Child = container;
        container.Children.Add(_left = new TextBlock { HorizontalAlignment = System.Windows.HorizontalAlignment.Left });
        container.Children.Add(_right = new TextBlock { HorizontalAlignment = System.Windows.HorizontalAlignment.Right });
        Inlines.Add(child);

        SetText();
    }
}

это не так. (Я смотрел довольно долго.)

A TextBlock определяет один блок текста и применяет к нему свойства обоснования. Потому что TextBlock и другие элементы WPF, естественно, авторазмер, подход использования двух из них, каждый с различными настройками по их обоснованию proprty, является правильным подходом.

они могут содержать <Span> и <Run> элементы, и @JMK указал на учебник кода

чтобы сделать то, что вам нужно, рассмотрите FlowDocument элемент и его содержимое, что позволит вам описать обоснования как иерархическую разметку XAML. А FlowDocument может потреблять очень небольшое количество места на экране.

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


если вы используете (или хотите использовать) шрифт фиксированной ширины, вы можете использовать String.PadRight. Например, если максимальная длина текста TextBox это 30 символов, звоните:

myTextBox.Text = myString.PadRight(29, ' ') + ":";

это заставит двоеточие выровнять вправо независимо от длины строки, выровненной слева. Невозможно выровнять текстовое поле как слева, так и справа. Я не парень WPF, поэтому мое следующее предложение также будет включать перевод на WPF equivelents из инструкций Windows Forms. Несмотря ни на что, еще одна вещь, которую вы могли бы сделать, если вам нужно использовать шрифт переменной ширины, было бы сделать это:

  • создайте класс, производный от TextBox.
  • переопределить OnPaint функция или WPF equivelent.
  • создать код, чтобы заполнить фон и границы, как вы хотите.
  • использовать Graphics.DrawString (или equivelent) выровнены влево для основной строки, а затем выровнены вправо для двоеточия. В обоих случаях с помощью ClientRectangle вашего базового класса в DrawString function.

помимо создания производного класса с пользовательским OnPaint функция, вам придется использовать какой-то обман.

Я желаю вам всего наилучшего.