我想要一个包含以下文本的文本块:
My associated textbox is :
文本左对齐,冒号右对齐。
我知道如何使用两个文本块来获得上面的输出。但是我想知道单个文本块是否适用于相同的行为?
TextBlock
本质上不支持对齐子元素的概念,但当然有一些可能的解决方法:
InlineUIContainer
在 TextBlock 内添加实际 UI 元素(您可以对齐这些元素)。我将通过创建一个带有 LeftAlignedText
和 RightAlignedText
属性的 ExtendedTextBlock
控件来为每个示例提供示例。使用方式如下:
<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>
TextBlock
添加了InlineUIContainer
控件,并保留了对“左”和“右”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();
}
}
InlineUIContainer
仅指定了两个TextBlock
。在这种情况下,我个人更倾向于编写两个TextBlock
。(如果可以的话,我建议将其拆分为两个答案。) - Rob PerkinsString.PadRight
。例如,如果TextBox
的最大文本长度为30个字符,请调用:myTextBox.Text = myString.PadRight(29, ' ') + ":";
OnPaint
函数或WPF等效函数。Graphics.DrawString
(或其等效项)向左对齐,然后对于冒号向右对齐。在两种情况下,都使用基类中的ClientRectangle
在DrawString函数
中。除了创建具有自定义OnPaint
函数的派生类之外,您还需要使用某种诡计。
祝您好运。
“value is {Value}:"
会产生<TextBlock Text="value is "/><TextBox Width="50" Text="{Binding Path=Value}"/><TextBlock Text=":"/>
。 - nmclean