我有一个GridView
,其中一个GridViewColumn
我希望生成这样的文字:
textBlock.Text = string.Format("{0} is doing {1} .......", a, b);
但a
和b
(视图中项目的属性)不应仅仅表示为纯文本,而应表示为Hyperlink
。
(另外:格式文本应取决于项目的类型)
如何以这种方式生成TextBlock
文本? (用于本地化)
问题更多:我应该自己写一些东西,还是框架提供了一种简单的方法?
答案 0 :(得分:20)
一个老问题,但我发现接受的答案绝对有点过分。您根本不需要解析格式化的文本!只需将其包裹在Span
元素中即可完成。
public class Attached
{
public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached(
"FormattedText",
typeof(string),
typeof(Attached),
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure, FormattedTextPropertyChanged));
public static void SetFormattedText(DependencyObject textBlock, string value)
{
textBlock.SetValue(FormattedTextProperty, value);
}
public static string GetFormattedText(DependencyObject textBlock)
{
return (string)textBlock.GetValue(FormattedTextProperty);
}
private static void FormattedTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBlock = d as TextBlock;
if (textBlock == null)
{
return;
}
var formattedText = (string)e.NewValue ?? string.Empty;
formattedText = string.Format("<Span xml:space=\"preserve\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">{0}</Span>", formattedText);
textBlock.Inlines.Clear();
using (var xmlReader = XmlReader.Create(new StringReader(formattedText)))
{
var result = (Span)XamlReader.Load(xmlReader);
textBlock.Inlines.Add(result);
}
}
}
现在,您可以在代码中使用FormattedText
附加属性:
string inlineExpression = "<Run Style=\"Theme.GrayText\">Once I saw a little bird, go hop, hop, hop.</Run>";
Attached.SetFormattedText(myTextBlock1, inlineExpression);
更重要的是,直接来自XAML:
<TextBlock ns:Attached.FormattedText="{Binding Content}" />
ns
是命名空间,您在{。}}中定义了Attached
类
答案 1 :(得分:8)
最近我遇到了同样的问题。所以我决定为TextBlock
实现附加属性,其值为string
类型,然后动态填充Inlines
集合。您可以简单地将属性值设置为以下内容:
string inlineExpression = "Once i saw a little <bold>bird</bold>, <span>go <bold>hop, hop, hop</bold></span>.";
InlineExpression.SetInlineExpression(myTextBlock1, inlineExpression);
还支持这些样式:
string inlineExpression = "<run style="Theme.GrayText">Once i saw a little bird, go hop, hop, hop.</run>";
InlineExpression.SetInlineExpression(myTextBlock1, inlineExpression);
您也可以以标准方式在XAML中使用此附加属性。
以下是公开此属性的类的代码:
public class InlineExpression
{
public static readonly DependencyProperty InlineExpressionProperty = DependencyProperty.RegisterAttached(
"InlineExpression", typeof(string), typeof(TextBlock), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure));
public static void SetInlineExpression(TextBlock textBlock, string value)
{
textBlock.SetValue(InlineExpressionProperty, value);
textBlock.Inlines.Clear();
if (string.IsNullOrEmpty(value))
return;
var descriptions = GetInlineDescriptions(value);
if (descriptions.Length == 0)
return;
var inlines = GetInlines(textBlock, descriptions);
if (inlines.Length == 0)
return;
textBlock.Inlines.AddRange(inlines);
}
public static string GetInlineExpression(TextBlock textBlock)
{
return (string)textBlock.GetValue(InlineExpressionProperty);
}
enum InlineType
{
Run,
LineBreak,
Span,
Bold,
Italic,
Hyperlink,
Underline
}
class InlineDescription
{
public InlineType Type { get; set; }
public string Text { get; set; }
public InlineDescription[] Inlines { get; set; }
public string StyleName { get; set; }
}
private static Inline[] GetInlines(FrameworkElement element, IEnumerable<InlineDescription> inlineDescriptions)
{
var inlines = new List<Inline>();
foreach (var description in inlineDescriptions)
{
var inline = GetInline(element, description);
if (inline != null)
inlines.Add(inline);
}
return inlines.ToArray();
}
private static Inline GetInline(FrameworkElement element, InlineDescription description)
{
Style style = null;
if (!string.IsNullOrEmpty(description.StyleName))
{
style = element.FindResource(description.StyleName) as Style;
if (style == null)
throw new InvalidOperationException("The style '" + description.StyleName + "' cannot be found");
}
Inline inline = null;
switch (description.Type)
{
case InlineType.Run:
var run = new Run(description.Text);
inline = run;
break;
case InlineType.LineBreak:
var lineBreak = new LineBreak();
inline = lineBreak;
break;
case InlineType.Span:
var span = new Span();
inline = span;
break;
case InlineType.Bold:
var bold = new Bold();
inline = bold;
break;
case InlineType.Italic:
var italic = new Italic();
inline = italic;
break;
case InlineType.Hyperlink:
var hyperlink = new Hyperlink();
inline = hyperlink;
break;
case InlineType.Underline:
var underline = new Underline();
inline = underline;
break;
}
if (inline != null)
{
var span = inline as Span;
if (span != null)
{
var childInlines = new List<Inline>();
foreach (var inlineDescription in description.Inlines)
{
var childInline = GetInline(element, inlineDescription);
if (childInline == null)
continue;
childInlines.Add(childInline);
}
span.Inlines.AddRange(childInlines);
}
if (style != null)
inline.Style = style;
}
return inline;
}
private static InlineDescription[] GetInlineDescriptions(string inlineExpression)
{
if (inlineExpression == null)
return new InlineDescription[0];
inlineExpression = inlineExpression.Trim();
if (inlineExpression.Length == 0)
return new InlineDescription[0];
inlineExpression = inlineExpression.Insert(0, @"<root>");
inlineExpression = inlineExpression.Insert(inlineExpression.Length, @"</root>");
var xmlTextReader = new XmlTextReader(new StringReader(inlineExpression));
var xmlDocument = new XmlDocument();
xmlDocument.Load(xmlTextReader);
var rootElement = xmlDocument.DocumentElement;
if (rootElement == null)
return new InlineDescription[0];
var inlineDescriptions = new List<InlineDescription>();
foreach (XmlNode childNode in rootElement.ChildNodes)
{
var description = GetInlineDescription(childNode);
if (description == null)
continue;
inlineDescriptions.Add(description);
}
return inlineDescriptions.ToArray();
}
private static InlineDescription GetInlineDescription(XmlNode node)
{
var element = node as XmlElement;
if (element != null)
return GetInlineDescription(element);
var text = node as XmlText;
if (text != null)
return GetInlineDescription(text);
return null;
}
private static InlineDescription GetInlineDescription(XmlElement element)
{
InlineType type;
var elementName = element.Name.ToLower();
switch (elementName)
{
case "run":
type = InlineType.Run;
break;
case "linebreak":
type = InlineType.LineBreak;
break;
case "span":
type = InlineType.Span;
break;
case "bold":
type = InlineType.Bold;
break;
case "italic":
type = InlineType.Italic;
break;
case "hyperlink":
type = InlineType.Hyperlink;
break;
case "underline":
type = InlineType.Underline;
break;
default:
return null;
}
string styleName = null;
var attribute = element.GetAttributeNode("style");
if (attribute != null)
styleName = attribute.Value;
string text = null;
var childDescriptions = new List<InlineDescription>();
if (type == InlineType.Run || type == InlineType.LineBreak)
{
text = element.InnerText;
}
else
{
foreach (XmlNode childNode in element.ChildNodes)
{
var childDescription = GetInlineDescription(childNode);
if (childDescription == null)
continue;
childDescriptions.Add(childDescription);
}
}
var inlineDescription = new InlineDescription
{
Type = type,
StyleName = styleName,
Text = text,
Inlines = childDescriptions.ToArray()
};
return inlineDescription;
}
private static InlineDescription GetInlineDescription(XmlText text)
{
var value = text.Value;
if (string.IsNullOrEmpty(value))
return null;
var inlineDescription = new InlineDescription
{
Type = InlineType.Run,
Text = value
};
return inlineDescription;
}
}
答案 2 :(得分:3)
在XAML中你可以这样做:
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink NavigateUri="{Binding AUri}">
<Run Text="{Binding A}"/>
</Hyperlink>
<Run Text=" is doing "/>
<Hyperlink NavigateUri="{Binding BUri}">
<Run Text="{Binding B}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
在代码背后可以做同样的事情,但我不推荐它,因为它涉及使用FrameworkElementFactories。