更改 TextBlock 的绑定文本中子字符串的颜色
Changing the colors of substrings within the bound Text of a TextBlock
我正在将一些 属性 绑定到我的 TextBlock
:
<TextBlock
Text="{Binding Status}"
Foreground="{Binding RealTimeStatus,Converter={my:RealTimeStatusToColorConverter}}"
/>
Status
是简单文本,RealTimeStatus
是 enum
。对于每个 enum
值,我正在更改我的 TextBlock
Foreground
颜色。
有时我的 Status
消息包含数字。该消息根据 enum
值获得适当的颜色,但我想知道我是否可以更改此消息中数字的颜色,以便数字与文本的其余部分具有不同的颜色。
编辑。
XAML
<TextBlock my:TextBlockExt.XAMLText="{Binding Status, Converter={my:RealTimeStatusToColorConverter}}"/>
转换器:
public class RealTimeStatusToColorConverter : MarkupExtension, IValueConverter
{
// One way converter from enum RealTimeStatus to color.
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is RealTimeStatus && targetType == typeof(Brush))
{
switch ((RealTimeStatus)value)
{
case RealTimeStatus.Cancel:
case RealTimeStatus.Stopped:
return Brushes.Red;
case RealTimeStatus.Done:
return Brushes.White;
case RealTimeStatus.PacketDelay:
return Brushes.Salmon;
default:
break;
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public RealTimeStatusToColorConverter()
{
}
// MarkupExtension implementation
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
您可以使用 Span,尽管设置您的 TextBlock 需要更多的工作。
看看 this page,我发现它相当简单但全面,我从中提取了以下片段:
<TextBlock Margin="10" TextWrapping="Wrap">
This <Span FontWeight="Bold">is</Span> a
<Span Background="Silver" Foreground="Maroon">TextBlock</Span>
with <Span TextDecorations="Underline">several</Span>
<Span FontStyle="Italic">Span</Span> elements,
<Span Foreground="Blue">
using a <Bold>variety</Bold> of <Italic>styles</Italic>
</Span>.
</TextBlock>
这里附上一个属性将任意文本解析为XAMLTextBlock
内容,包括Run
、Span
、Bold
等. 这具有普遍有用的优点。
我建议你写一个 ValueConverter
用适当的标记替换 Status
文本中的数字,这样当你给它这个文本时...
Error number 34: No custard for monkey kitty.
...它将把它转换成这个文本:
Error number <Span Foreground="Red">34</Span>: No custard for monkey kitty.
您已经知道如何进行值转换器,而使用正则表达式的文本替换则完全是另一回事。
XAML 用法:
<TextBlock
soex:TextBlockExt.XAMLText={Binding Status, Converter={my:redNumberConverter}}"
/>
如果是我,我会疯狂地将颜色设置为 ConverterParameter。
这是附件 属性:
的 C#
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace Whosebug.Examples
{
public static class TextBlockExt
{
public static String GetXAMLText(TextBlock obj)
{
return (String)obj.GetValue(XAMLTextProperty);
}
public static void SetXAMLText(TextBlock obj, String value)
{
obj.SetValue(XAMLTextProperty, value);
}
/// <summary>
/// Convert raw string from ViewModel into formatted text in a TextBlock:
///
/// @"This <Bold>is a test <Italic>of the</Italic></Bold> text."
///
/// Text will be parsed as XAML TextBlock content.
///
/// See WPF TextBlock documentation for full formatting. It supports spans and all kinds of things.
///
/// </summary>
public static readonly DependencyProperty XAMLTextProperty =
DependencyProperty.RegisterAttached("XAMLText", typeof(String), typeof(TextBlockExt),
new PropertyMetadata("", XAMLText_PropertyChanged));
private static void XAMLText_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TextBlock)
{
var ctl = d as TextBlock;
try
{
// XAML needs a containing tag with a default namespace. We're parsing
// TextBlock content, so make the parent a TextBlock to keep the schema happy.
// TODO: If you want any content not in the default schema, you're out of luck.
var strText = String.Format(@"<TextBlock xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">{0}</TextBlock>", e.NewValue);
TextBlock parsedContent = System.Windows.Markup.XamlReader.Load(GenerateStreamFromString(strText)) as TextBlock;
// The Inlines collection contains the structured XAML content of a TextBlock
ctl.Inlines.Clear();
// UI elements are removed from the source collection when the new parent
// acquires them, so pass in a copy of the collection to iterate over.
ctl.Inlines.AddRange(parsedContent.Inlines.ToList());
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(String.Format("Error in Ability.CAPS.WPF.UIExtensions.TextBlock.XAMLText_PropertyChanged: {0}", ex.Message));
throw;
}
}
}
public static Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
}
}
我正在将一些 属性 绑定到我的 TextBlock
:
<TextBlock
Text="{Binding Status}"
Foreground="{Binding RealTimeStatus,Converter={my:RealTimeStatusToColorConverter}}"
/>
Status
是简单文本,RealTimeStatus
是 enum
。对于每个 enum
值,我正在更改我的 TextBlock
Foreground
颜色。
有时我的 Status
消息包含数字。该消息根据 enum
值获得适当的颜色,但我想知道我是否可以更改此消息中数字的颜色,以便数字与文本的其余部分具有不同的颜色。
编辑。
XAML
<TextBlock my:TextBlockExt.XAMLText="{Binding Status, Converter={my:RealTimeStatusToColorConverter}}"/>
转换器:
public class RealTimeStatusToColorConverter : MarkupExtension, IValueConverter
{
// One way converter from enum RealTimeStatus to color.
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is RealTimeStatus && targetType == typeof(Brush))
{
switch ((RealTimeStatus)value)
{
case RealTimeStatus.Cancel:
case RealTimeStatus.Stopped:
return Brushes.Red;
case RealTimeStatus.Done:
return Brushes.White;
case RealTimeStatus.PacketDelay:
return Brushes.Salmon;
default:
break;
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public RealTimeStatusToColorConverter()
{
}
// MarkupExtension implementation
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
您可以使用 Span,尽管设置您的 TextBlock 需要更多的工作。
看看 this page,我发现它相当简单但全面,我从中提取了以下片段:
<TextBlock Margin="10" TextWrapping="Wrap">
This <Span FontWeight="Bold">is</Span> a
<Span Background="Silver" Foreground="Maroon">TextBlock</Span>
with <Span TextDecorations="Underline">several</Span>
<Span FontStyle="Italic">Span</Span> elements,
<Span Foreground="Blue">
using a <Bold>variety</Bold> of <Italic>styles</Italic>
</Span>.
</TextBlock>
这里附上一个属性将任意文本解析为XAMLTextBlock
内容,包括Run
、Span
、Bold
等. 这具有普遍有用的优点。
我建议你写一个 ValueConverter
用适当的标记替换 Status
文本中的数字,这样当你给它这个文本时...
Error number 34: No custard for monkey kitty.
...它将把它转换成这个文本:
Error number <Span Foreground="Red">34</Span>: No custard for monkey kitty.
您已经知道如何进行值转换器,而使用正则表达式的文本替换则完全是另一回事。
XAML 用法:
<TextBlock
soex:TextBlockExt.XAMLText={Binding Status, Converter={my:redNumberConverter}}"
/>
如果是我,我会疯狂地将颜色设置为 ConverterParameter。
这是附件 属性:
的 C#using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace Whosebug.Examples
{
public static class TextBlockExt
{
public static String GetXAMLText(TextBlock obj)
{
return (String)obj.GetValue(XAMLTextProperty);
}
public static void SetXAMLText(TextBlock obj, String value)
{
obj.SetValue(XAMLTextProperty, value);
}
/// <summary>
/// Convert raw string from ViewModel into formatted text in a TextBlock:
///
/// @"This <Bold>is a test <Italic>of the</Italic></Bold> text."
///
/// Text will be parsed as XAML TextBlock content.
///
/// See WPF TextBlock documentation for full formatting. It supports spans and all kinds of things.
///
/// </summary>
public static readonly DependencyProperty XAMLTextProperty =
DependencyProperty.RegisterAttached("XAMLText", typeof(String), typeof(TextBlockExt),
new PropertyMetadata("", XAMLText_PropertyChanged));
private static void XAMLText_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TextBlock)
{
var ctl = d as TextBlock;
try
{
// XAML needs a containing tag with a default namespace. We're parsing
// TextBlock content, so make the parent a TextBlock to keep the schema happy.
// TODO: If you want any content not in the default schema, you're out of luck.
var strText = String.Format(@"<TextBlock xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">{0}</TextBlock>", e.NewValue);
TextBlock parsedContent = System.Windows.Markup.XamlReader.Load(GenerateStreamFromString(strText)) as TextBlock;
// The Inlines collection contains the structured XAML content of a TextBlock
ctl.Inlines.Clear();
// UI elements are removed from the source collection when the new parent
// acquires them, so pass in a copy of the collection to iterate over.
ctl.Inlines.AddRange(parsedContent.Inlines.ToList());
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(String.Format("Error in Ability.CAPS.WPF.UIExtensions.TextBlock.XAMLText_PropertyChanged: {0}", ex.Message));
throw;
}
}
}
public static Stream GenerateStreamFromString(string s)
{
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
}
}