WPF文本框更改文本的背景颜色,而不是全部文本框

发布于 2025-01-29 21:40:10 字数 99 浏览 3 评论 0原文

我想知道是否有一种方法可以更改textbox内文本背景的颜色,而不是整个textbox。 就像当您突出显示/选择文本时一样。

I would like to know if there is a way to change the color of the background of the text inside a TextBox and not for the whole TextBox.
Like when you highlight/select the text.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

稀香 2025-02-05 21:40:10

文本框通常不支持彩色文本或丰富的文本格式。根据您的方案,您必须使用textblockrichtextbox

TextBlock

您可以直接处理文本元素:

<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使用文本来创建内联元素 - 到内线转换器。由于我们无法直接绑定到textblock.inlines属性,因此我们使用textblock.text.text属性作为虚拟绑定目标:

rightlightighlightinfo.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.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

如果您需要允许用户输入,则必须使用a <<代码> 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 doesn't support coloured text or rich text formatting in general. Depending on your scenario, you would have to go with a TextBlock or RichtextBox.

TextBlock

You can either handle the text elements directly:

<TextBlock>
  <Run Text="This is some" />
  <Run Text="red"
       Background="Red" />
  <Run Text="text." />
</TextBlock>

Or in case you need to find a particular text, handle the text pointers:

<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);
}

To make highlighting dynamic you can use a MultiBinding to create the inline elements using a text-to-Inline converter. Since we can't bind directly to the TextBlock.Inlines property, we use the TextBlock.Text property as a dummy binding target:

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

In case you need to allow user input, you would have to use a 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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文