我想动态格式化TextBlock中的特定单词,因为它绑定到我的对象。我正在考虑使用Converter,但使用以下解决方案只将标签直接添加到文本中(而不是显示格式化)。
public class TextBlockFormatter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
string regexp = @"\p{L}+#\d{4}";
if (value != null) {
return Regex.Replace(value as string, regexp, m => string.Format("<Bold>{0}</Bold>", m.Value));
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
return null;
}
}
答案 0 :(得分:2)
这不是试图回答这个问题......这是对问题评论中的问题的回应。
是的@Blam,你可以格式化单个单词,甚至是TextBlock
中的字符......你需要使用Run
(或者你可以将Run
替换为TextBlock
)。无论哪种方式,您还可以将数据绑定到其中任何一个上的Text
属性:
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Run Text="This" FontWeight="Bold" Foreground="Red" />
<Run Text="text" FontSize="18" />
<Run Text="is" FontStyle="Italic" />
<Run Text="in" FontWeight="SemiBold" Background="LightGreen" />
<Run Text="one" FontFamily="Candara" FontSize="20" />
<Run Text="TextBlock" FontWeight="Bold" Foreground="Blue" />
</TextBlock>
更新&gt;&gt;&gt;
现在关于这个问题,我想可以在Run
中使用这些DataTemplate
元素,并从数据中生成它们......本例中的数据必须是具有(显然)Text
属性的类,还有可用于将数据绑定到Run
样式属性的格式化属性。
它会尴尬,因为TextBlock
没有ItemsSource
属性,你可以绑定你的单词类集合...也许你可以使用{{ 1}}对于那部分...只是在这里大声思考......我现在要停止了。
更新&gt;&gt;&gt;
@KrzysztofBzowski,遗憾的是Converter
属性不 a TextBlock.Inlines
,因此您将无法将数据绑定到它。然而,它让我思考,我做了另一次搜索,找到了关于Jevgeni Tsaikin的.NET实验室的Binding text containing tags to TextBlock inlines using attached property in Silverlight for Windows Phone 7文章。
这将涉及你宣布附属物和DependencyProperty
,但看起来很有希望......试一试。并且不要担心它是针对Silverlight的......如果它在Silverlight中有效,那么它将在WPF中运行。
答案 1 :(得分:2)
我最近不得不通过为TextBlocks编写Blend行为来解决这个问题。
可以在XAML中声明一个Highlight元素列表,您可以在其中指定要突出显示的文本,您希望该文本的颜色以及它的字体粗细(可以根据需要轻松添加更多格式设置属性)。
它通过循环所需的高光来工作,从TextBlock.ContentStart TextPointer开始扫描每个短语的TextBlock。找到短语后,它可以构建一个TextRange,它可以应用格式化选项。
如果TextBlock Text属性也是数据绑定,它应该有效,因为我附加到绑定目标更新事件。
请参阅下面的行为代码和XAML中的示例
public class TextBlockHighlightBehaviour : Behavior<TextBlock>
{
private EventHandler<DataTransferEventArgs> targetUpdatedHandler;
public List<Highlight> Highlights { get; set; }
public TextBlockHighlightBehaviour()
{
this.Highlights = new List<Highlight>();
}
#region Behaviour Overrides
protected override void OnAttached()
{
base.OnAttached();
targetUpdatedHandler = new EventHandler<DataTransferEventArgs>(TextBlockBindingUpdated);
Binding.AddTargetUpdatedHandler(this.AssociatedObject, targetUpdatedHandler);
// Run the initial behaviour logic
HighlightTextBlock(this.AssociatedObject);
}
protected override void OnDetaching()
{
base.OnDetaching();
Binding.RemoveTargetUpdatedHandler(this.AssociatedObject, targetUpdatedHandler);
}
#endregion
#region Private Methods
private void TextBlockBindingUpdated(object sender, DataTransferEventArgs e)
{
var textBlock = e.TargetObject as TextBlock;
if (textBlock == null)
return;
if(e.Property.Name == "Text")
HighlightTextBlock(textBlock);
}
private void HighlightTextBlock(TextBlock textBlock)
{
foreach (var highlight in this.Highlights)
{
foreach (var range in FindAllPhrases(textBlock, highlight.Text))
{
if (highlight.Foreground != null)
range.ApplyPropertyValue(TextElement.ForegroundProperty, highlight.Foreground);
if(highlight.FontWeight != null)
range.ApplyPropertyValue(TextElement.FontWeightProperty, highlight.FontWeight);
}
}
}
private List<TextRange> FindAllPhrases(TextBlock textBlock, string phrase)
{
var result = new List<TextRange>();
var position = textBlock.ContentStart;
while (position != null)
{
var range = FindPhrase(position, phrase);
if (range != null)
{
result.Add(range);
position = range.End;
}
else
position = null;
}
return result;
}
// This method will search for a specified phrase (string) starting at a specified position.
private TextRange FindPhrase(TextPointer position, string phrase)
{
while (position != null)
{
if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
{
string textRun = position.GetTextInRun(LogicalDirection.Forward);
// Find the starting index of any substring that matches "phrase".
int indexInRun = textRun.IndexOf(phrase);
if (indexInRun >= 0)
{
TextPointer start = position.GetPositionAtOffset(indexInRun);
TextPointer end = start.GetPositionAtOffset(phrase.Length);
return new TextRange(start, end);
}
}
position = position.GetNextContextPosition(LogicalDirection.Forward);
}
// position will be null if "phrase" is not found.
return null;
}
#endregion
}
public class Highlight
{
public string Text { get; set; }
public Brush Foreground { get; set; }
public FontWeight FontWeight { get; set; }
}
XAML中的示例用法:
<TextBlock Text="Here is some text">
<i:Interaction.Behaviors>
<behaviours:TextBlockHighlightBehaviour>
<behaviours:TextBlockHighlightBehaviour.Highlights>
<behaviours:Highlight Text="some" Foreground="{StaticResource GreenBrush}" FontWeight="Bold" />
</behaviours:TextBlockHighlightBehaviour.Highlights>
</behaviours:TextBlockHighlightBehaviour>
</i:Interaction.Behaviors>
</TextBlock>
您需要导入Blend interactiveity命名空间和您的行为命名空间:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviours="clr-namespace:YourProject.Behviours"
答案 2 :(得分:0)
我有一个类似的用例,我需要使用RichTextBox构建一个文本编辑器。但是,所有文本格式的更改:字体,颜色,斜体,粗体必须动态地反映在TextBlock上。我发现很少有文章指向 Textblock.inlines.Add(),这看起来很有帮助但只允许一次更改或附加到现有文本。
但是, Textblock.inlines.ElementAt(要格式化的现有文本的索引)可用于将所需的文本格式应用于位于该索引处的文本。以下是解决此问题的伪方法。我希望这会有所帮助:
For RichTextBox:
selectedText.ApplyPropertyValue(TextElement.FontFamilyProperty, cbFontFamily.SelectedValue.ToString());
但是,为了使Textblock格式化工作,我不得不使用Run run = new Run()概念,它允许并使用:
Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString(SelectedColorText))
FontFamily = new FontFamily(cbFontFamily.SelectedValue.ToString())
FontStyle = FontStyles.Italic
TextDecorations = TextDecorations.Underline
TextDecorations = TextDecorations.Strikethrough
FontWeight = (FontWeight)new FontWeightConverter().ConvertFromString(cbFontWeightBox.SelectedItem.ToString())
此外,我创建了一个包含各种字段和构造函数的类。我还创建了一个基于自定义的类字典来捕获RichTextbbox中所做的所有更改。最后,我通过forloop在字典中应用了所有捕获的信息。
TextBlock.Inlines.ElementAt(mItemIndex).Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString(dictionaryItem.Value._applyColor.ToString()));
TextBlock.Inlines.ElementAt(mItemIndex).FontFamily = new FontFamily(ftItem.Value._applyFontFamily.ToString());
TextBlock.Inlines.ElementAt(mItemIndex).FontStyle = FontStyles.Italic;
TextBlock.Inlines.ElementAt(mItemIndex).TextDecorations = TextDecorations.Underline;
TextBlock.Inlines.ElementAt(mItemIndex).TextDecorations = TextDecorations.Strikethrough;