WPF TextBox 更改文本的背景颜色而不是整个 TextBox
WPF TextBox change background color of text and not whole TextBox
我想知道是否有办法更改 TextBox
内而不是整个 TextBox
内文本的背景颜色。
就像你 highlight/select 文本一样。
TextBox
通常不支持彩色文本或富文本格式。根据您的情况,您必须使用 TextBlock
或 RichtextBox
.
文本块
您可以直接处理文本元素:
<TextBlock>
<Run Text="This is some" />
<Run Text="red"
Background="Red" />
<Run Text="text." />
</TextBlock>
或者如果您需要查找特定文本,请处理文本指针:
<TextBlock x:Name="ColouredTextBlock" />
private void OnLoaded(object sender, EventArgs e)
{
var text = "This is some red text.";
var highlightText = "red";
this.ColouredTextBlock.Text = text;
int highlightTextIndex = this.ColouredTextbox.Text.IndexOf(highlightText);
TextPointer textStartPointer = this.ColouredTextbox.ContentStart.DocumentStart.GetInsertionPosition(LogicalDirection.Forward);
var highlightTextRange = new TextRange(textStartPointer.GetPositionAtOffset(highlightTextIndex), textStartPointer.GetPositionAtOffset(highlightTextIndex + highlightText.Length));
highlightTextRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Red);
}
要使突出显示动态化,您可以使用 MultiBinding
通过 text-to-Inline 转换器创建内联元素。由于我们不能直接绑定到 TextBlock.Inlines
属性,我们使用 TextBlock.Text
属性 作为虚拟绑定目标:
HighlightInfo.cs
public struct HighlightInfo
{
/// <summary>
/// Set Range parameter: inclusive start index and exclusive end index
/// </summary>
/// <param name="highlightRange">inclusive start index and exclusive end index</param>
public HighlightInfo(Range highlightRange, Color foreground, Color background)
{
HighlightRange = highlightRange;
Foreground = foreground;
Background = background;
}
public System.Range HighlightRange { get; }
public int HighlightRangeLength => this.HighlightRange.End.Value - this.HighlightRange.Start.Value;
public Color Foreground { get; }
public Color Background { get; }
}
TextToInlineConverter.cs
public class TextToInlineConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string sourceText = values.OfType<string>().First();
if (string.IsNullOrWhiteSpace(sourceText))
{
return Binding.DoNothing;
}
TextBlock textBlock = values.OfType<TextBlock>().First();
IEnumerable<HighlightInfo> highlightInfos = values.OfType<IEnumerable<HighlightInfo>>().First();
List<HighlightInfo> sortedHighlightInfos = highlightInfos
.OrderBy(highlightInfo => highlightInfo.HighlightRange.Start.Value)
.ToList();
int highlightStartIndex = sortedHighlightInfos.FirstOrDefault().HighlightRange.Start.Value;
bool hasPreccedingNonHighlightText = highlightStartIndex > 0;
if (hasPreccedingNonHighlightText)
{
string preceedingText = sourceText.Substring(0, highlightStartIndex);
textBlock.Inlines.Add(preceedingText);
}
CreateHighlightTextElements(sourceText, textBlock, sortedHighlightInfos);
int highlightEndIndex = sortedHighlightInfos.LastOrDefault().HighlightRange.End.Value;
bool hasTrailingNonHighlightText = highlightEndIndex < sourceText.Length;
if (hasTrailingNonHighlightText)
{
string trailingText = sourceText.Substring(highlightEndIndex);
textBlock.Inlines.Add(trailingText);
}
// We are binding to the 'TextBlock.Text' property as a dummy target, so we don't want to set it.
// We have already modified the 'TextBlcok.Inlines' collection.
return Binding.DoNothing;
}
private void CreateHighlightTextElements(string sourceText, TextBlock textBlock, List<HighlightInfo> sortedHighlightInfos)
{
for (int index = 0; index < sortedHighlightInfos.Count; index++)
{
HighlightInfo highlightInfo = sortedHighlightInfos[index];
var highlightText = new Run(sourceText.Substring(highlightInfo.HighlightRange.Start.Value, highlightInfo.HighlightRangeLength))
{
Foreground = new SolidColorBrush(highlightInfo.Foreground),
Background = new SolidColorBrush(highlightInfo.Background),
};
textBlock.Inlines.Add(highlightText);
if (index + 1 < sortedHighlightInfos.Count)
{
HighlightInfo nextHighlightInfo = sortedHighlightInfos[index + 1];
var nonHighlightTextRangeLength = nextHighlightInfo.HighlightRange.Start.Value - highlightInfo.HighlightRange.End.Value;
bool hasEnclosedNonHighlightText = nonHighlightTextRangeLength > 0;
if (hasEnclosedNonHighlightText)
{
highlightText = new Run(sourceText.Substring(highlightInfo.HighlightRange.End.Value, nonHighlightTextRangeLength));
textBlock.Inlines.Add(highlightText);
}
}
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
MainWindow.xaml.cs
partial class MainWIndow : Window
{
public ObservableCollection<HighlightInfo> HighlightInfos { get; }
public string TextValue { get; }
public MainWindow()
{
InitializeComponent();
this.TextValue = "This is some red and orange and bluegreen text.";
this.HighlightInfos = new ObservableCollection<HighlightInfo>()
{
new HighlightInfo(new Range(
this.TextValue.IndexOf("red"),
this.TextValue.IndexOf("red") + "red".Length),
Colors.Black,
Colors.Red),
new HighlightInfo(new Range(
this.TextValue.IndexOf("orange"),
this.TextValue.IndexOf("orange") + "orange".Length),
Colors.Black,
Colors.Orange),
new HighlightInfo(new Range(
this.TextValue.IndexOf("blue"),
this.TextValue.IndexOf("blue") + "blue".Length),
Colors.Black,
Colors.Blue),
new HighlightInfo(new Range(
this.TextValue.IndexOf("green"),
this.TextValue.IndexOf("green") + "green".Length),
Colors.Black,
Colors.Green),
};
}
}
MainWindow.xaml
<Window>
<Window.Resources>
<local:TextToInlineConverter x:Key="TextToInlineConverter" />
</Window.Resources>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource TextToInlineConverter}">
<Binding Path="TextValue" />
<Binding Path="HighlightInfos" />
<Binding RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Window>
富文本框
如果您需要允许用户输入,则必须使用 RichTextBox
:
<RichTextBlock x:Name="ColouredRichTextBox" />
private void OnLoaded(object sender, EventArgs e)
{
var text = "This is some red text.";
var highlightText = "red";
this.ColouredRichTextBox.Document = new FlowDocument(new Paragraph(new Run(text)));
TextPointer textStartPointer = this.ColouredRichTextBox.Document.ContentStart.DocumentStart.GetInsertionPosition(LogicalDirection.Forward);
var highlightTextRange = new TextRange(textStartPointer.GetPositionAtOffset(highlightTextIndex), textStartPointer.GetPositionAtOffset(highlightTextIndex + highlightText.Length));
highlightTextRange .ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Red);
}
我想知道是否有办法更改 TextBox
内而不是整个 TextBox
内文本的背景颜色。
就像你 highlight/select 文本一样。
TextBox
通常不支持彩色文本或富文本格式。根据您的情况,您必须使用 TextBlock
或 RichtextBox
.
文本块
您可以直接处理文本元素:
<TextBlock>
<Run Text="This is some" />
<Run Text="red"
Background="Red" />
<Run Text="text." />
</TextBlock>
或者如果您需要查找特定文本,请处理文本指针:
<TextBlock x:Name="ColouredTextBlock" />
private void OnLoaded(object sender, EventArgs e)
{
var text = "This is some red text.";
var highlightText = "red";
this.ColouredTextBlock.Text = text;
int highlightTextIndex = this.ColouredTextbox.Text.IndexOf(highlightText);
TextPointer textStartPointer = this.ColouredTextbox.ContentStart.DocumentStart.GetInsertionPosition(LogicalDirection.Forward);
var highlightTextRange = new TextRange(textStartPointer.GetPositionAtOffset(highlightTextIndex), textStartPointer.GetPositionAtOffset(highlightTextIndex + highlightText.Length));
highlightTextRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Red);
}
要使突出显示动态化,您可以使用 MultiBinding
通过 text-to-Inline 转换器创建内联元素。由于我们不能直接绑定到 TextBlock.Inlines
属性,我们使用 TextBlock.Text
属性 作为虚拟绑定目标:
HighlightInfo.cs
public struct HighlightInfo
{
/// <summary>
/// Set Range parameter: inclusive start index and exclusive end index
/// </summary>
/// <param name="highlightRange">inclusive start index and exclusive end index</param>
public HighlightInfo(Range highlightRange, Color foreground, Color background)
{
HighlightRange = highlightRange;
Foreground = foreground;
Background = background;
}
public System.Range HighlightRange { get; }
public int HighlightRangeLength => this.HighlightRange.End.Value - this.HighlightRange.Start.Value;
public Color Foreground { get; }
public Color Background { get; }
}
TextToInlineConverter.cs
public class TextToInlineConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string sourceText = values.OfType<string>().First();
if (string.IsNullOrWhiteSpace(sourceText))
{
return Binding.DoNothing;
}
TextBlock textBlock = values.OfType<TextBlock>().First();
IEnumerable<HighlightInfo> highlightInfos = values.OfType<IEnumerable<HighlightInfo>>().First();
List<HighlightInfo> sortedHighlightInfos = highlightInfos
.OrderBy(highlightInfo => highlightInfo.HighlightRange.Start.Value)
.ToList();
int highlightStartIndex = sortedHighlightInfos.FirstOrDefault().HighlightRange.Start.Value;
bool hasPreccedingNonHighlightText = highlightStartIndex > 0;
if (hasPreccedingNonHighlightText)
{
string preceedingText = sourceText.Substring(0, highlightStartIndex);
textBlock.Inlines.Add(preceedingText);
}
CreateHighlightTextElements(sourceText, textBlock, sortedHighlightInfos);
int highlightEndIndex = sortedHighlightInfos.LastOrDefault().HighlightRange.End.Value;
bool hasTrailingNonHighlightText = highlightEndIndex < sourceText.Length;
if (hasTrailingNonHighlightText)
{
string trailingText = sourceText.Substring(highlightEndIndex);
textBlock.Inlines.Add(trailingText);
}
// We are binding to the 'TextBlock.Text' property as a dummy target, so we don't want to set it.
// We have already modified the 'TextBlcok.Inlines' collection.
return Binding.DoNothing;
}
private void CreateHighlightTextElements(string sourceText, TextBlock textBlock, List<HighlightInfo> sortedHighlightInfos)
{
for (int index = 0; index < sortedHighlightInfos.Count; index++)
{
HighlightInfo highlightInfo = sortedHighlightInfos[index];
var highlightText = new Run(sourceText.Substring(highlightInfo.HighlightRange.Start.Value, highlightInfo.HighlightRangeLength))
{
Foreground = new SolidColorBrush(highlightInfo.Foreground),
Background = new SolidColorBrush(highlightInfo.Background),
};
textBlock.Inlines.Add(highlightText);
if (index + 1 < sortedHighlightInfos.Count)
{
HighlightInfo nextHighlightInfo = sortedHighlightInfos[index + 1];
var nonHighlightTextRangeLength = nextHighlightInfo.HighlightRange.Start.Value - highlightInfo.HighlightRange.End.Value;
bool hasEnclosedNonHighlightText = nonHighlightTextRangeLength > 0;
if (hasEnclosedNonHighlightText)
{
highlightText = new Run(sourceText.Substring(highlightInfo.HighlightRange.End.Value, nonHighlightTextRangeLength));
textBlock.Inlines.Add(highlightText);
}
}
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
MainWindow.xaml.cs
partial class MainWIndow : Window
{
public ObservableCollection<HighlightInfo> HighlightInfos { get; }
public string TextValue { get; }
public MainWindow()
{
InitializeComponent();
this.TextValue = "This is some red and orange and bluegreen text.";
this.HighlightInfos = new ObservableCollection<HighlightInfo>()
{
new HighlightInfo(new Range(
this.TextValue.IndexOf("red"),
this.TextValue.IndexOf("red") + "red".Length),
Colors.Black,
Colors.Red),
new HighlightInfo(new Range(
this.TextValue.IndexOf("orange"),
this.TextValue.IndexOf("orange") + "orange".Length),
Colors.Black,
Colors.Orange),
new HighlightInfo(new Range(
this.TextValue.IndexOf("blue"),
this.TextValue.IndexOf("blue") + "blue".Length),
Colors.Black,
Colors.Blue),
new HighlightInfo(new Range(
this.TextValue.IndexOf("green"),
this.TextValue.IndexOf("green") + "green".Length),
Colors.Black,
Colors.Green),
};
}
}
MainWindow.xaml
<Window>
<Window.Resources>
<local:TextToInlineConverter x:Key="TextToInlineConverter" />
</Window.Resources>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource TextToInlineConverter}">
<Binding Path="TextValue" />
<Binding Path="HighlightInfos" />
<Binding RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Window>
富文本框
如果您需要允许用户输入,则必须使用 RichTextBox
:
<RichTextBlock x:Name="ColouredRichTextBox" />
private void OnLoaded(object sender, EventArgs e)
{
var text = "This is some red text.";
var highlightText = "red";
this.ColouredRichTextBox.Document = new FlowDocument(new Paragraph(new Run(text)));
TextPointer textStartPointer = this.ColouredRichTextBox.Document.ContentStart.DocumentStart.GetInsertionPosition(LogicalDirection.Forward);
var highlightTextRange = new TextRange(textStartPointer.GetPositionAtOffset(highlightTextIndex), textStartPointer.GetPositionAtOffset(highlightTextIndex + highlightText.Length));
highlightTextRange .ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Red);
}