前言

本章讲述正确添加语言资源的方式,以及一段语言资源的多种样式显示。

例如:“@Winter,你好!感谢已使用软件 800 天!”

 

在添加如上多语言资源项时,“XX,你好!感谢已使用软件 X 天!”

那么,你是怎么添加语言资源的呢?

分别添加,“,你好!”、“感谢已使用软件”、“年”3个,再通过界面绑定动态变量 昵称和使用天数

假如你是按照如上添加语言资源的,那么问题来了,添加如上英文语言资源呢?是不是也分别添加单个资源,再拼凑绑定?

添加语言资源

正确的做法是,添加整个语言资源,“{0},你好!感谢已使用软件 {1} 天!”

原因:使用格式化的语言资源,那么将中文资源翻译成英文或者其它语言后,得到的译文才符合原有的含义。

不然,一段一段翻译后的文本拼接,得到的只会是,中式英文之类的。。。

语言格式化控件

在添加了语言资源后,如何在WPF界面显示呢?

简单的文本样式

假如只是实现简单的文本拼接,且样式相同时,可以直接绑定动态变量值 - 昵称和使用年限,然后通过StringFormat或者Conveter去处理格式化文本。

  • 如果只有一个动态变量,直接使用StringFormat处理即可。Text="{Binding Name,StringFormat={StaticResource TheFormatedText}}"
  • 如果多个动态变量,可以使用多重绑定+Converter,实现文本格式化。

详细可查看 WPF StringFormat 格式化文本

复杂的文本样式

假如格式化文本,需要实现复杂的样式和操作,例如:

  1. 文本+按钮
  2. 文本+超链接
  3. 加粗文本+普通文本+红色文本

以上,如何处理?

语言格式化控件实现

Demo显示效果:

WPF 语言格式化文本控件_控件

 1. 添加一个继承TextBlock的用户控件ComplexTextBlock

1     /// <summary>
2 /// 解决复杂文本格式化样式的文本框控件
3 /// 如"已使用软件 {0} 天",天数需要标红加粗,或者用于【文本】【文字按钮】【文本】的组合
4 /// </summary>
5 public class ComplexTextBlock : TextBlock
6 {
7
8

2. 重写文本依赖属性

为了监听文本变更,所以重写文本的依赖属性。文本变更事件处理,之后会详细介绍~

1     public new static DependencyProperty TextProperty =
2 DependencyProperty.Register("Text", typeof(string), typeof(ComplexTextBlock), new PropertyMetadata(TextPropertyChanged));
3
4 public static string GetText(DependencyObject element)
5 {
6 return (string)element.GetValue(TextProperty);
7 }
8 public static void SetText(DependencyObject element, string value)
9 {
10 element.SetValue(TextProperty, value);
11 }
12
13 private static void TextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
14 {
15 LoadComplexContent(d);
16

3. 添加动态变量显示的控件列表

如“@Winter,你好!感谢已使用软件 800 天,可查看详情!”,可以将昵称、使用时间、详情,分别设置为文本控件、文本控件、超链接按钮,然后添加到动态控件列表中。

 

1     public static DependencyProperty ContentFormatsProperty =
2 DependencyProperty.Register("ContentFormats", typeof(ContentFormatsCollection), typeof(ComplexTextBlock),
3 new PropertyMetadata(default(ContentFormatsCollection), ContentFormatsPropertyChanged));
4
5 /// <summary>
6 /// 格式化内容列表
7 /// </summary>
8 public ContentFormatsCollection ContentFormats
9 {
10 get => (ContentFormatsCollection)GetValue(ContentFormatsProperty);
11 set => SetValue(ContentFormatsProperty, value);
12 }
13
14 private static void ContentFormatsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
15 {
16 LoadComplexContent(d);
17

 

4. 处理格式化文本

处理方法,主要是将当前格式化的文本拆分为多个文本段落和格式化字符“{0}”,然后将待显示的动态变量(文本控件/按钮等)替换拆分后列表中的格式化字符。组合成完整的显示文本。

其中,需要注意的是,文本的样式继承。

1     private const string FormattedKey = "{0}";
2
3 /// <summary>
4 /// 加载复杂文本
5 /// </summary>
6 /// <param name="dependencyObject"></param>
7 private static void LoadComplexContent(DependencyObject dependencyObject)
8 {
9 if (!(dependencyObject is ComplexTextBlock complexTextBlock))
10 {
11 return;
12 }
13
14 string text = GetText(complexTextBlock);
15 var contentFormats = complexTextBlock.ContentFormats;
16
17 if (string.IsNullOrEmpty(text) || contentFormats == null || contentFormats.Count == 0)
18 {
19 return;
20 }
21
22 for (int i = 0; i < contentFormats.Count; i++)
23 {
24 text = text.Replace(i.ToString(), "0");
25 }
26
27 var list = GetTextList(text);
28
29 //清空当前文本
30 complexTextBlock.Text = null;
31 //分段加载文本
32 var stackPanel = new StackPanel();
33 stackPanel.Orientation = Orientation.Horizontal;
34 stackPanel.VerticalAlignment = VerticalAlignment.Center;
35
36 int formatIndex = 0;
37 foreach (var paraText in list)
38 {
39 if (paraText == FormattedKey)
40 {
41 stackPanel.Children.Add(contentFormats[formatIndex++]);
42 }
43 else
44 {
45 var textLine = new TextBlock();
46 if (complexTextBlock.Style != null)
47 {
48 textLine.Style = complexTextBlock.Style;
49 }
50 else
51 {
52 textLine.VerticalAlignment = complexTextBlock.VerticalAlignment;
53 textLine.HorizontalAlignment = complexTextBlock.HorizontalAlignment;
54 textLine.Background = complexTextBlock.Background;
55 textLine.FontFamily = complexTextBlock.FontFamily;
56 textLine.FontSize = complexTextBlock.FontSize;
57 textLine.Foreground = complexTextBlock.Foreground;
58 textLine.FontWeight = complexTextBlock.FontWeight;
59 textLine.FontStyle = complexTextBlock.FontStyle;
60 }
61 textLine.Text = paraText;
62 stackPanel.Children.Add(textLine);
63 }
64 }
65 complexTextBlock.Inlines.Add(stackPanel);
66 }
67
68 /// <summary>
69 /// 获取分段文本列表
70 /// </summary>
71 /// <param name="text"></param>
72 /// <returns></returns>
73 private static List<string> GetTextList(string text)
74 {
75 var list = new List<string>();
76 var formatIndex = text.IndexOf(FormattedKey, StringComparison.Ordinal);
77
78 //1.不存在格式化关键字,则直接返回当前文本
79 if (formatIndex == -1)
80 {
81 list.Add(text);
82 return list;
83 }
84
85 //2.存在格式化关键字
86 if (formatIndex == 0)
87 {
88 list.Add(FormattedKey);
89 }
90 else
91 {
92 list.Add(text.Substring(0, formatIndex));
93 list.Add(FormattedKey);
94 }
95
96 //获取下一格式化文本
97 if (formatIndex < text.Length)
98 {
99 list.AddRange(GetTextList(text.Substring(formatIndex + FormattedKey.Length)));
100 }
101
102 return list;
103

5. 控件的使用

界面显示:

WPF 语言格式化文本控件_超链接_02

调用实现:

1     <local:ComplexTextBlock Text="小王,好好{0},详见{1}!" Style="{StaticResource ComplexTextBlockStyle}" Margin="0 10 0 0">
2 <local:ComplexTextBlock.ContentFormats>
3 <local:ContentFormatsCollection>
4 <Button Content="学习" Click="ButtonBase_OnClick" VerticalAlignment="Center"></Button>
5 <Button x:Name="LinkedButton" Content="学习计划" Click="LinkedButton_OnClick" Style="{StaticResource LinkeButton}" VerticalAlignment="Center"/>
6 </local:ContentFormatsCollection>
7 </local:ComplexTextBlock.ContentFormats>
8 </local:ComplexTextBlock>

详细代码实现,可查看​​Github源码Demo​

 


作者:唐宋元明清2188

本文版权归作者所有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。