c# - C# WPF - 在 TextBlocks 中对齐单行文本
问题描述
我有一个 StackPanel,里面有几个 TextBlock,如下所示:
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="First is quite lengthy" />
<TextBlock Text="This one's shorter"/>
<TextBlock Text="This one too"/>
<TextBlock Text="This one is a bit longer again"/>
</StackPanel>
我想证明所有这些都是合理的,以便 TextBlocks 的左侧和右侧都垂直对齐 - 我该怎么做?
上面的代码如下所示:
粗略估计我想要实现的目标:
我尝试过使用 TextAlignment(Justify 对我不起作用)、FontStretch、HorizontalAlignment、DockPanel 和 Viewbox(因为我想保持字体大小不变,所以它不起作用)。如果不对文本中的一些空格进行硬编码,我可以做些什么来实现这一点?
解决方案
我惊讶地发现 WPF 默认情况下不支持对齐的单行 TextBlocks。但是,您可以相对轻松地自己实现此行为。我拼凑了一个快速的解决方案,它提供了一个用户控件,其唯一目的是绘制一个合理的单行文本。
解决方案非常简单,不支持文本换行、边距或任何其他特殊布局情况,只有最基本的 DependencyProperties。不过,这应该是一个很好的起点。
public partial class JustifiedLine : UserControl
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(JustifiedLine),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty MinSpaceWidthProperty = DependencyProperty.Register(
"MinSpaceWidth",
typeof(double),
typeof(JustifiedLine),
new FrameworkPropertyMetadata(5.0, FrameworkPropertyMetadataOptions.AffectsRender));
public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public double MinSpaceWidth
{
get => (double)GetValue(MinSpaceWidthProperty);
set => SetValue(MinSpaceWidthProperty, value);
}
public JustifiedLine()
{
InitializeComponent();
}
protected override void OnRender(DrawingContext drawingContext)
{
string[] words = Text.Split(' ');
if (words.Length == 0)
return;
int numValidWords = 0;
double totalWordsWidth = 0;
/* add widths of all words */
for (int i = 0; i < words.Length; i++)
{
if (String.IsNullOrWhiteSpace(words[i]))
continue;
FormattedText fText = MakeFormattedText(words[i]);
totalWordsWidth += fText.Width;
numValidWords++;
}
double fullWidth = GetFullWidth();
double spaceWidth = (fullWidth - totalWordsWidth) / (numValidWords - 1);
if (spaceWidth < MinSpaceWidth)
spaceWidth = MinSpaceWidth;
double currentWidth = 0;
for (int i = 0; i < words.Length; i++)
{
if (String.IsNullOrWhiteSpace(words[i]))
continue;
FormattedText fText = MakeFormattedText(words[i]);
drawingContext.DrawText(fText, new Point(currentWidth, 0));
currentWidth += fText.Width + spaceWidth;
/* if Height isn't specified, automatically set from text height */
if (double.IsNaN(Height))
Height = fText.Height;
}
}
/* return either width of this control, or the parent control if not set. If neither is set, return 0.0 */
private double GetFullWidth()
{
if (!double.IsNaN(Width))
return Width;
FrameworkElement parent = Parent as FrameworkElement;
if (parent != null && !double.IsNaN(parent.ActualWidth))
return parent.ActualWidth;
return 0.0;
}
/* might want to bind font etc. to dependency property, these here are just placeholders */
private FormattedText MakeFormattedText(string text)
{
return new FormattedText(
text,
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
16,
Brushes.White,
VisualTreeHelper.GetDpi(this).PixelsPerDip);
}
}
如果这样使用:
<StackPanel Width="300">
<usercontrols:JustifiedLine Text="First is quite lengthy"/>
<usercontrols:JustifiedLine Text="This one's shorter"/>
<usercontrols:JustifiedLine Text="This one too"/>
<usercontrols:JustifiedLine Text="This one is a bit longer again"/>
</StackPanel>
xmlns:usercontrols="clr-namespace:MyProject.controls.usercontrols"
这是我的结果:
推荐阅读
- reactjs - 如何更改 TextField 日期选择器的日历图标的颜色?在 Material-UI React 中
- excel - Power Automate 和 Excel - 提取多个唯一值
- javascript - 用于阻止特定页面元素加载的浏览器扩展
- sql - Postgres - 模式删除后恢复/维护权限
- swiftui - SwiftUI 更改内联 navigationBarTitleDisplayMode 的导航栏背景颜色
- flutter - 如何让 Flutter 对话框消失?
- sql - 通过分组获取用户每月的最新访问日期,即使它为空
- swagger - OpenAPI v3 / Swagger - 调用函数并向其发送 json 字典
- javascript - Javascript 使用 For 循环为 false
- java - 为什么当我尝试转换我的 DTO 时出现 StackOverFlow