[英]WPF TextBlock formatting bold from string property
我已将 TextBlock 文本绑定到字符串属性。
Xaml 看起来像:
<TextBlock Text="{Binding Message}" TextWrapping="Wrap"/>
ModelView class 上的属性如下所示:
private string message;
public string Message
{
get { return message; }
set
{
message = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Message)));
}
}
我希望能够使用粗体等文本块格式化功能。
例如:
Message = "Some string with <Bold>bold</Bold> words";
在运行时 Textblock 应该出现:
一些带有粗体字的字符串
这个问题的正确和更好的解决方案是什么?
搜索 MVVM 解决方案(无代码隐藏)。
我会使用自定义附加属性来做到这一点。 不是直接绑定到TextBlock
的Text
属性,而是绑定到自己的 FormattedText 附加属性,然后使用PropertyChangedCallback
通过以编程方式设置TextBlock
的Inlines
来处理格式化部分。
XAML 足够简单,但这是因为大部分工作是由附加属性完成的:
<TextBlock local:TextBlockFormatter.FormattedText="{Binding FormattedText, Mode=OneWay}" />
这是一个仅查找粗体和斜体格式标记的附加属性示例:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Xml.Linq;
...
public class TextBlockFormatter
{
public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
"FormattedText",
typeof(string),
typeof(TextBlockFormatter),
new FrameworkPropertyMetadata(null, OnFormattedTextChanged));
public static void SetFormattedText(UIElement element, string value)
{
element.SetValue(FormattedTextProperty, value);
}
public static string GetFormattedText(UIElement element)
{
return (string)element.GetValue(FormattedTextProperty);
}
private static void OnFormattedTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textblock = (TextBlock)d;
var formatted = (string)e.NewValue;
if (string.IsNullOrEmpty(formatted))
textblock.Text = "";
else
{
textblock.Inlines.Clear();
try
{
var nodeStack = new Stack<StyleStackNode>();
var root = XElement.Parse("<root>" + formatted + "</root>");
nodeStack.Push(new StyleStackNode(root.FirstNode));
while (nodeStack.Count > 0)
{
var format = nodeStack.Pop();
if (format.Node.NextNode != null)
nodeStack.Push(new StyleStackNode(format.Node.NextNode, copyFormats: format.Formatters));
if (format.Node is XElement tag && tag.FirstNode != null)
{
var adding = new StyleStackNode(tag.FirstNode, copyFormats: format.Formatters);
if (0 == string.Compare(tag.Name.LocalName, "bold", true))
adding.Formatters.Add(run => run.FontWeight = FontWeights.Bold);
else if (0 == string.Compare(tag.Name.LocalName, "italic", true))
adding.Formatters.Add(run => run.FontStyle = FontStyles.Italic);
nodeStack.Push(adding);
}
else if (format.Node is XText textNode)
{
var run = new Run();
foreach (var formatter in format.Formatters)
formatter(run);
run.Text = textNode.Value;
textblock.Inlines.Add(run);
}
}
}
catch
{
textblock.Text = formatted;
}
}
}
class StyleStackNode
{
public XNode Node;
public List<Action<Run>> Formatters = new List<Action<Run>>();
public StyleStackNode(XNode node, IEnumerable<Action<Run>> copyFormats = null)
{
Node = node;
if (copyFormats != null)
Formatters.AddRange(copyFormats);
}
}
}
您必须进行一些解析,但这可以使用内联来完成。 在CodeProject上有一个很好的评论示例,尽管它确实有一些限制,但我认为这是一个很好的起点。 还有另一个关于这里的一些不同策略的SO帖子
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.