TextBlock,其中一些文本左对齐,其余文本右对齐

时间:2013-12-14 17:16:22

标签: c# wpf xaml

我想要一个包含以下文字的文本块:

My associated textbox is                :

文本左对齐,冒号右对齐。

我知道如何使用两个文本块获得上述输出。但我想知道是否适用于单个文本块?

3 个答案:

答案 0 :(得分:8)

TextBlock本质上反对对齐儿童的概念,但当然有一些可能的 hacks 解决方法:

  1. 填写空格以给出对齐的外观。
  2. 使用InlineUIContainer在TextBlock中添加实际的UI元素(您可以对齐)。
  3. 我将通过创建具有ExtendedTextBlockLeftAlignedText属性的RightAlignedText控件来举例说明。用法是这样的:

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

    1)用空格填充。

    对于这种方法,我借用this answer来获取文本字符串的实际宽度。这个想法基本上是从控件的实际宽度中减去文本的总宽度,并在它们之间插入适当数量的空格。

    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,并保留对“左”和“右”TextBlock的引用,并根据需要设置其文本。

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

答案 1 :(得分:3)

不是。 (我好好看了一会儿。)

TextBlock定义一个文本块,并将对齐属性应用于它。因为TextBlock和其他WPF元素自然是自动调整大小,所以使用其中两个元素的方法是正确的方法,每个方法都有不同的设置理由。

它们可以包含<Span><Run>元素,而@JMK指向代码教程

要做你需要的,考虑FlowDocument元素及其内容,这将允许你将理由描述为分层XAML标记。 FlowDocument可以消耗非常少量的屏幕空间。

或者,考虑使用{{1}实现一个转换器,在该转换器中,您可以通过添加空格和冒号来发现TextBlock的宽度和要转换的字符串的宽度,并相应地调整字符串中的间距。 } class。

答案 2 :(得分:1)

如果您正在使用(或愿意使用)固定宽度字体,则可以使用String.PadRight。例如,如果TextBox的最大文本长度为30个字符,请调用:

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

无论左对齐的字符串长度如何,这将使冒号对齐。没有办法左右对齐TextBox。我不是WPF的人,所以我的下一个建议还涉及从Windows Forms指令转换为WPF equivelents。无论如何,如果你必须使用可变宽度字体,你可以做的另一件事就是这样做:

  • 创建一个派生自TextBox的类。
  • 覆盖OnPaint功能或WPF equivelent。
  • 创建代码以填充背景和边框。
  • 使用Graphics.DrawString(或equivelent)左对齐主字符串,然后右对齐冒号。在这两种情况下都使用ClientRectangle中基类的DrawString function

除了使用自定义OnPaint函数创建派生类之外,您还必须使用某种技巧。

我祝你万事如意。