前言

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

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

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

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

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

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

添加语言资源

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

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

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

语言格式化控件

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

简单的文本样式

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

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

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

复杂的文本样式

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

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

以上,如何处理?

语言格式化控件实现

Demo显示效果:

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

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

2. 重写文本依赖属性

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

     public new static DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ComplexTextBlock), new PropertyMetadata(TextPropertyChanged)); public static string GetText(DependencyObject element)
{
return (string)element.GetValue(TextProperty);
}
public static void SetText(DependencyObject element, string value)
{
element.SetValue(TextProperty, value);
} private static void TextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LoadComplexContent(d);
}

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

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

     public static DependencyProperty ContentFormatsProperty =
DependencyProperty.Register("ContentFormats", typeof(ContentFormatsCollection), typeof(ComplexTextBlock),
new PropertyMetadata(default(ContentFormatsCollection), ContentFormatsPropertyChanged)); /// <summary>
/// 格式化内容列表
/// </summary>
public ContentFormatsCollection ContentFormats
{
get => (ContentFormatsCollection)GetValue(ContentFormatsProperty);
set => SetValue(ContentFormatsProperty, value);
} private static void ContentFormatsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
LoadComplexContent(d);
}

4. 处理格式化文本

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

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

     private const string FormattedKey = "{0}";

     /// <summary>
/// 加载复杂文本
/// </summary>
/// <param name="dependencyObject"></param>
private static void LoadComplexContent(DependencyObject dependencyObject)
{
if (!(dependencyObject is ComplexTextBlock complexTextBlock))
{
return;
} string text = GetText(complexTextBlock);
var contentFormats = complexTextBlock.ContentFormats; if (string.IsNullOrEmpty(text) || contentFormats == null || contentFormats.Count == )
{
return;
} for (int i = ; i < contentFormats.Count; i++)
{
text = text.Replace(i.ToString(), "");
} var list = GetTextList(text); //清空当前文本
complexTextBlock.Text = null;
//分段加载文本
var stackPanel = new StackPanel();
stackPanel.Orientation = Orientation.Horizontal;
stackPanel.VerticalAlignment = VerticalAlignment.Center; int formatIndex = ;
foreach (var paraText in list)
{
if (paraText == FormattedKey)
{
stackPanel.Children.Add(contentFormats[formatIndex++]);
}
else
{
var textLine = new TextBlock();
if (complexTextBlock.Style != null)
{
textLine.Style = complexTextBlock.Style;
}
else
{
textLine.VerticalAlignment = complexTextBlock.VerticalAlignment;
textLine.HorizontalAlignment = complexTextBlock.HorizontalAlignment;
textLine.Background = complexTextBlock.Background;
textLine.FontFamily = complexTextBlock.FontFamily;
textLine.FontSize = complexTextBlock.FontSize;
textLine.Foreground = complexTextBlock.Foreground;
textLine.FontWeight = complexTextBlock.FontWeight;
textLine.FontStyle = complexTextBlock.FontStyle;
}
textLine.Text = paraText;
stackPanel.Children.Add(textLine);
}
}
complexTextBlock.Inlines.Add(stackPanel);
} /// <summary>
/// 获取分段文本列表
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
private static List<string> GetTextList(string text)
{
var list = new List<string>();
var formatIndex = text.IndexOf(FormattedKey, StringComparison.Ordinal); //1.不存在格式化关键字,则直接返回当前文本
if (formatIndex == -)
{
list.Add(text);
return list;
} //2.存在格式化关键字
if (formatIndex == )
{
list.Add(FormattedKey);
}
else
{
list.Add(text.Substring(, formatIndex));
list.Add(FormattedKey);
} //获取下一格式化文本
if (formatIndex < text.Length)
{
list.AddRange(GetTextList(text.Substring(formatIndex + FormattedKey.Length)));
} return list;
}

5. 控件的使用

界面显示:

调用实现:

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

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

WPF 语言格式化文本控件的更多相关文章

  1. 解决方案:带格式化文本控件( RichText)的模板如果在InfoPath的浏览器中加载可能出现 COM 组件的80040154错误

      建议大家在微软的组件出现问题时,在GOOGLE上搜索解决方案,一般来说,总有结果:  带格式化文本控件( RichText)的模板如果在InfoPath的浏览器中加载,可能出现 COM 组件的80 ...

  2. WPF编程:textbox控件文本框数据显示最后一行

    WPF编程:textbox控件文本框数据显示最后一行 TextBox控件在接收大量数据的时候,滚动条一般在最上方,如何使滚动条随着数据的接收而向下滚动呢?比如有一个TextBox'控件txbRecvD ...

  3. WCF学习(二)对控件简单了解以及4个文本控件的简介

    WPF基础控件 系统默认提供的基础控件: 文本控件介绍与用法 Label控件 label控件:一般用户描述性文字显示. 在Label控件使用时,一般给予用户提示.用法上没有什么很特殊的,label控件 ...

  4. WPF Step By Step 控件介绍

    WPF Step By Step 控件介绍 回顾 上一篇,我们主要讨论了WPF的几个重点的基本知识的介绍,本篇,我们将会简单的介绍几个基本控件的简单用法,本文会举几个项目中的具体的例子,结合这些 例子 ...

  5. WPF中的ControlTemplate(控件模板)(转)

    原文地址 http://www.cnblogs.com/zhouyinhui/archive/2007/03/28/690993.html WPF中的ControlTemplate(控件模板)     ...

  6. WPF:DataTemplateSelector设置控件不同的样式

    原文 WPF:DataTemplateSelector设置控件不同的样式 最近想实现这么个东西,一个ListBox, 里面的ListBoxItem可能是文本框.下拉框.日期选择控件等等. 很自然的想到 ...

  7. WPF基础篇之控件模板(ControlTemplate)

    WPF中每一个控件都有一个默认的模板,该模板描述了控件的外观以及外观对外界刺激所做出的反应.我们可以自定义一个模板来替换掉控件的默认模板以便打造个性化的控件. 与Style不同,Style只能改变控件 ...

  8. AvalonEdit-基于WPF的代码显示控件

    AvalonEdit是基于WPF的代码显示控件,项目地址:https://github.com/icsharpcode/AvalonEdit,支持C#,javascript,C++,XML,HTML, ...

  9. WPF中的ControlTemplate(控件模板)

    原文:WPF中的ControlTemplate(控件模板) WPF中的ControlTemplate(控件模板)                                             ...

随机推荐

  1. request.getRequestDispatcher跳转jsp页面失败

    我在JS里面写了个Ajax,传值给控制器,然后利用request.getRequestDispatcher(),打算跳转至另外一个页面.但是没有跳转成功,运行之后没反应. 在网上搜了资料发现,利用aj ...

  2. 回顾4180天在腾讯使用C#的历程,开启新的征途

    今天是2018年8月8日,已经和腾讯解除劳动关系,我的公司正式开始运营,虽然还有很多事情需要理清,公司官网也没有做,接下来什么事情都需要自己去完成了,需要一步一个脚印去完善,开启一个新的征途,我将在博 ...

  3. 【安富莱专题教程第6期】SEGGER的J-Scope波形上位机软件,RTT模式波形上传速度可狂飙到500KB/S左右

    说明:1.在实际项目中,很多时候,我们需要将传感器或者ADC的数值以波形的形式显示.通常的解决办法是用串口上位机,USB接口上位机或者MDK的逻辑分析仪功能,使用这三种方式都比较繁琐.本期专题为大家讲 ...

  4. FFmpeg命令行工具学习(一):查看媒体文件头信息工具ffprobe

    一.简述 ffprobe是ffmpeg命令行工具中相对简单的,此命令是用来查看媒体文件格式的工具. 二.命令格式 在命令行中输入如下格式的命令: ffprobe [文件名] 三.使用ffprobe查看 ...

  5. [Swift]LeetCode93. 复原IP地址 | Restore IP Addresses

    Given a string containing only digits, restore it by returning all possible valid IP address combina ...

  6. [Swift]LeetCode937. 重新排列日志文件 | Reorder Log Files

    You have an array of logs.  Each log is a space delimited string of words. For each log, the first w ...

  7. 值得收藏的Mybatis通用Mapper使用大全。

    引言 由于小编的记性不太好,每次在写代码的时候总是把通用mapper的方法记错,所以今天把通用mapper的常用方法做一下总结,方便以后直接查看.好了,不废话啦. 引包 <!-- 通用Mappe ...

  8. 微信小程序自动化测试实践

    由于腾讯系QQ.微信等都是基于腾讯自研X5内核,不是google原生webview(其实就是进行了二次定制).实质上也是混合应用的一种,现在很多app产品也开始流行采用X5内核作为其内嵌web浏览服务 ...

  9. js的预解析

    在ES6之前,变量使用var声明,会存在变量的预解析(函数也有预解析).ES6引了let和const,但是现阶段ES6并没有完全普及,而且很多比较老的代码都还是按照ES5的标准甚至是ES3的标准来书写 ...

  10. Linux 的文件权限和目录配置

    1.Linux文件属性 用root用户登录linux后,执行 ls -al 命令查看文件.显示如下: 文件属性示意图如下: 第一列代表这个文件的类型和权限 第一个字符代表这个文件是:目录.文件或链接文 ...