WPF 语言格式化文本控件
前言
本章讲述正确添加语言资源的方式,以及一段语言资源的多种样式显示。
例如:“@winter,你好!感谢已使用软件 800 天!”
在添加如上多语言资源项时,“xx,你好!感谢已使用软件 x 天!”
那么,你是怎么添加语言资源的呢?
分别添加,“,你好!”、“感谢已使用软件”、“年”3个,再通过界面绑定动态变量 昵称和使用天数?
假如你是按照如上添加语言资源的,那么问题来了,添加如上英文语言资源呢?是不是也分别添加单个资源,再拼凑绑定?
添加语言资源
正确的做法是,添加整个语言资源,“{0},你好!感谢已使用软件 {1} 天!”
原因:使用格式化的语言资源,那么将中文资源翻译成英文或者其它语言后,得到的译文才符合原有的含义。
不然,一段一段翻译后的文本拼接,得到的只会是,中式英文之类的。。。
语言格式化控件
在添加了语言资源后,如何在wpf界面显示呢?
简单的文本样式
假如只是实现简单的文本拼接,且样式相同时,可以直接绑定动态变量值 - 昵称和使用年限,然后通过stringformat或者conveter去处理格式化文本。
- 如果只有一个动态变量,直接使用stringformat处理即可。text="{binding name,stringformat={staticresource theformatedtext}}"
- 如果多个动态变量,可以使用多重绑定+converter,实现文本格式化。
复杂的文本样式
假如格式化文本,需要实现复杂的样式和操作,例如:
- 文本+按钮
- 文本+超链接
- 加粗文本+普通文本+红色文本
以上,如何处理?
语言格式化控件实现
demo显示效果:
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. 控件的使用
界面显示:
调用实现:
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
上一篇: LOJ#2552. 「CTSC2018」假面(期望 背包)
下一篇: ie下警告console未定义