欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

WPF 语言格式化文本控件

程序员文章站 2022-06-30 12:10:34
前言 本章讲述正确添加语言资源的方式,以及一段语言资源的多种样式显示。 例如:“@Winter,你好!感谢已使用软件 800 天!” 在添加如上多语言资源项时,“XX,你好!感谢已使用软件 X 天!” 那么,你是怎么添加语言资源的呢? 分别添加,“,你好!”、“感谢已使用软件”、“年”3个,再通过界 ......

前言

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

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

 

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

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

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

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

添加语言资源

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

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

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

语言格式化控件

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

简单的文本样式

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

  • 如果只有一个动态变量,直接使用stringformat处理即可。text="{binding name,stringformat={staticresource theformatedtext}}"
  • 如果多个动态变量,可以使用多重绑定+converter,实现文本格式化。

复杂的文本样式

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

  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 语言格式化文本控件

调用实现:

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 linkedtextblock}" verticalalignment="center"/>
6             </local:contentformatscollection>
7         </local:complextextblock.contentformats>
8     </local:complextextblock>

详细代码实现,可查看github源码demo