[英]WPF TextBlock formatting bold from string property
I have binded TextBlock text to a string property.我已将 TextBlock 文本绑定到字符串属性。
Xaml look like: Xaml 看起来像:
<TextBlock Text="{Binding Message}" TextWrapping="Wrap"/>
Property on the ModelView class look like: ModelView class 上的属性如下所示:
private string message;
public string Message
{
get { return message; }
set
{
message = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Message)));
}
}
I want to be able to use Textblock formatting abilities such as bold.我希望能够使用粗体等文本块格式化功能。
for example:例如:
Message = "Some string with <Bold>bold</Bold> words";
On run time Textblock should present:在运行时 Textblock 应该出现:
Some string with bold words一些带有粗体字的字符串
What is the right and better solution for this problem?这个问题的正确和更好的解决方案是什么?
Searching for MVVM solution (without code behind).搜索 MVVM 解决方案(无代码隐藏)。
I would do this using an custom attached property.我会使用自定义附加属性来做到这一点。 Instead of binding directly to the TextBlock
's Text
property, you would bind to your own FormattedText attached property and then use a PropertyChangedCallback
to handle the formatting part by programmatically setting the TextBlock
's Inlines
.不是直接绑定到TextBlock
的Text
属性,而是绑定到自己的 FormattedText 附加属性,然后使用PropertyChangedCallback
通过以编程方式设置TextBlock
的Inlines
来处理格式化部分。
The XAML is simple enough but that's because most of the work is done by the attached property: XAML 足够简单,但这是因为大部分工作是由附加属性完成的:
<TextBlock local:TextBlockFormatter.FormattedText="{Binding FormattedText, Mode=OneWay}" />
This is a an example of an attached property which only looks for bold and italic formatting tags:这是一个仅查找粗体和斜体格式标记的附加属性示例:
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);
}
}
}
You'd have to do some parsing but this can be accomplished using Inlines.您必须进行一些解析,但这可以使用内联来完成。 There's a well commented example of doing this over on CodeProject , though it does have some limitations this is a good starting point I think.在CodeProject上有一个很好的评论示例,尽管它确实有一些限制,但我认为这是一个很好的起点。 There's also another SO post about some different strategies here还有另一个关于这里的一些不同策略的SO帖子
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.