• WPF 语言格式化文本控件


    前言

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

    例如:“@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

    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 LinkeButton}" VerticalAlignment="Center"/>
    6             </local:ContentFormatsCollection>
    7         </local:ComplexTextBlock.ContentFormats>
    8     </local:ComplexTextBlock>

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

  • 相关阅读:
    anaconda 离线安装大包
    Openpose 安装问题解决
    Linux grep log文件及find命令学习
    整理了一些常用编程软件(方便自己下载)
    Docker安装es7.6和kibana7.6(并解决Unable to revive connection: http://192.168.162.139:9200/的问题)
    Jsr303分组校验和自定义注解校验
    Spring Cloud整合Oss
    Linux:vim
    Linux:挂载命令
    SpringBoot整合SpringSecurity:集中式项目
  • 原文地址:https://www.cnblogs.com/kybs0/p/9688933.html
Copyright © 2020-2023  润新知