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> 5public class ComplexTextBlock : TextBlock 6{ 7 8}
2. 重寫文字依賴屬性
為了監聽文字變更,所以重寫文字的依賴屬性。文字變更事件處理,之後會詳細介紹~
1public new static DependencyProperty TextProperty = 2DependencyProperty.Register("Text", typeof(string), typeof(ComplexTextBlock), new PropertyMetadata(TextPropertyChanged)); 3 4public static string GetText(DependencyObject element) 5{ 6return (string)element.GetValue(TextProperty); 7} 8public static void SetText(DependencyObject element, string value) 9{ 10element.SetValue(TextProperty, value); 11} 12 13private static void TextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 14{ 15LoadComplexContent(d); 16}
3. 新增動態變數顯示的控制元件列表
如“@ Winter ,你好!感謝已使用軟體 800 天,可檢視 詳情 !”,可以將 暱稱、使用時間、詳情 ,分別設定為 文字控制元件、文字控制元件、超連結按鈕 ,然後新增到動態控制元件列表中。
1public static DependencyProperty ContentFormatsProperty = 2DependencyProperty.Register("ContentFormats", typeof(ContentFormatsCollection), typeof(ComplexTextBlock), 3new PropertyMetadata(default(ContentFormatsCollection), ContentFormatsPropertyChanged)); 4 5/// <summary> 6/// 格式化內容列表 7/// </summary> 8public ContentFormatsCollection ContentFormats 9{ 10get => (ContentFormatsCollection)GetValue(ContentFormatsProperty); 11set => SetValue(ContentFormatsProperty, value); 12} 13 14private static void ContentFormatsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 15{ 16LoadComplexContent(d); 17}
4. 處理格式化文字
處理方法,主要是將當前格式化的文字拆分為多個文字段落和格式化字元“{0}”,然後將待顯示的動態變數(文字控制元件/按鈕等)替換拆分後列表中的格式化字元。組合成完整的顯示文字。
其中,需要注意的是,文字的樣式繼承。
1private const string FormattedKey = "{0}"; 2 3/// <summary> 4/// 載入複雜文字 5/// </summary> 6/// <param name="dependencyObject"></param> 7private static void LoadComplexContent(DependencyObject dependencyObject) 8{ 9if (!(dependencyObject is ComplexTextBlock complexTextBlock)) 10{ 11return; 12} 13 14string text = GetText(complexTextBlock); 15var contentFormats = complexTextBlock.ContentFormats; 16 17if (string.IsNullOrEmpty(text) || contentFormats == null || contentFormats.Count == 0) 18{ 19return; 20} 21 22for (int i = 0; i < contentFormats.Count; i++) 23{ 24text = text.Replace(i.ToString(), "0"); 25} 26 27var list = GetTextList(text); 28 29//清空當前文字 30complexTextBlock.Text = null; 31//分段載入文字 32var stackPanel = new StackPanel(); 33stackPanel.Orientation = Orientation.Horizontal; 34stackPanel.VerticalAlignment = VerticalAlignment.Center; 35 36int formatIndex = 0; 37foreach (var paraText in list) 38{ 39if (paraText == FormattedKey) 40{ 41stackPanel.Children.Add(contentFormats[formatIndex++]); 42} 43else 44{ 45var textLine = new TextBlock(); 46if (complexTextBlock.Style != null) 47{ 48textLine.Style = complexTextBlock.Style; 49} 50else 51{ 52textLine.VerticalAlignment = complexTextBlock.VerticalAlignment; 53textLine.HorizontalAlignment = complexTextBlock.HorizontalAlignment; 54textLine.Background = complexTextBlock.Background; 55textLine.FontFamily = complexTextBlock.FontFamily; 56textLine.FontSize = complexTextBlock.FontSize; 57textLine.Foreground = complexTextBlock.Foreground; 58textLine.FontWeight = complexTextBlock.FontWeight; 59textLine.FontStyle = complexTextBlock.FontStyle; 60} 61textLine.Text = paraText; 62stackPanel.Children.Add(textLine); 63} 64} 65complexTextBlock.Inlines.Add(stackPanel); 66} 67 68/// <summary> 69/// 獲取分段文字列表 70/// </summary> 71/// <param name="text"></param> 72/// <returns></returns> 73private static List<string> GetTextList(string text) 74{ 75var list = new List<string>(); 76var formatIndex = text.IndexOf(FormattedKey, StringComparison.Ordinal); 77 78//1.不存在格式化關鍵字,則直接返回當前文字 79if (formatIndex == -1) 80{ 81list.Add(text); 82return list; 83} 84 85//2.存在格式化關鍵字 86if (formatIndex == 0) 87{ 88list.Add(FormattedKey); 89} 90else 91{ 92list.Add(text.Substring(0, formatIndex)); 93list.Add(FormattedKey); 94} 95 96//獲取下一格式化文字 97if (formatIndex < text.Length) 98{ 99list.AddRange(GetTextList(text.Substring(formatIndex + FormattedKey.Length))); 100} 101 102return list; 103}