.NET Framework Developer Center > .NET Development Forums > Windows Presentation Foundation (WPF) > Search a text in WPF RichTextBox & replace its font.
Ask a questionAsk a question
 

AnswerSearch a text in WPF RichTextBox & replace its font.

  • Friday, November 06, 2009 2:16 PMRikz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Hi,
    I m using WPF RichTextBox(System.Windows.Controls.RichTextBox) but i am not getting a direct way to Search a specific word mentioned in RichTextBox & change its FontStyle.
    Please help..!!

Answers

  • Saturday, November 07, 2009 9:07 AMRahul P Nath Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Hi,
    Here is a small sample in vb

    <Grid>
            <RichTextBox Height="165" Margin="27,12,62,85" Name="RichTextBox1" Width="189" />
            <Button Height="23" Margin="82,0,121,20" Name="Button1" VerticalAlignment="Bottom">Button</Button>
        </Grid>

    Class Window1
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
            Dim objtextRange As TextRange
            Dim lstWordstoBeMatched As New List(Of String)
            lstWordstoBeMatched.Add("Hello")
            lstWordstoBeMatched.Add("to")
            Dim objWordStartPoint As TextPointer
            Dim objWordEndPoint As TextPointer
    
            objtextRange = New TextRange(RichTextBox1.Document.ContentStart, RichTextBox1.Document.ContentEnd)
            Dim strText As String
            strText = objtextRange.Text
            Dim lstMatchGroup As MatchCollection
            Dim objStart As TextPointer
            objStart = RichTextBox1.Document.ContentStart
            For Each strMatch In lstWordstoBeMatched
                lstMatchGroup = Regex.Matches(strText, strMatch)
                For Each objMatch As Match In lstMatchGroup
                    objWordStartPoint = GoToPoint(objStart, objMatch.Index)
                    objWordEndPoint = GoToPoint(objStart, objMatch.Index + objMatch.Length)
                    objtextRange = New TextRange(objWordStartPoint, objWordEndPoint)
                    objtextRange.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold)
                Next
            Next
    
        End Sub
    
        Private Sub Window1_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
            RichTextBox1.Document.Blocks.Clear()
            Dim obj As New Paragraph
            obj.Inlines.Add("Hello weelcome to the program.Hello how are you.to the message")
            RichTextBox1.Document.Blocks.Add(obj)
        End Sub
    
    
        Public Function GoToPoint(ByVal start As TextPointer, ByVal x As Integer) As TextPointer
            Dim out As TextPointer = start
            Dim i As Integer = 0
            Do While i < x
                If out.GetPointerContext(LogicalDirection.Backward) = TextPointerContext.Text Or _
                     out.GetPointerContext(LogicalDirection.Backward) = TextPointerContext.None Then
                    i += 1
                End If
                If out.GetPositionAtOffset(1, LogicalDirection.Forward) Is Nothing Then
                    Return out
                Else
                    out = out.GetPositionAtOffset(1, LogicalDirection.Forward)
                End If
            Loop
            Return out
        End Function
    
    
    End Class
    Here I am entering the sample text in the code behind and the list of words to be made bold also .
    Whatever is passed in the list will be make bold.

    Hope it helps
    Please mark posts as answers/helpful if it answers your query. This would be helpful for others facing the same kind of problem
    • Marked As Answer byRikz Saturday, November 07, 2009 9:17 AM
    •  

All Replies

  • Friday, November 06, 2009 10:12 PMgav135 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Has Code

    Operating on the FlowDocument behind the RichTextBox works for me.

    In the piece of code below, chatTextBox is a RichTextBox. DisplayMessage receives a message from a network socket, I'm not sure if the use of Dispatcher.Invoke is required in all situations, but it is in mine.

    Each time I receive a message, I create a new Paragraph for it and append it to the text in the RTB. Whilst constructing the paragraph, I do any keyword colour replacements I wish to using regex.

    The key is that a Paragraph is composed of a set of Run's. To change the FontStyle (Foreground colour in my case), you need to create a Run within the Run, so the XAML will go from <Run>Some text with blue text</Run> to <Run>Some text with </Run><Run Foreground="Blue">blue</Run><Run> text</Run>, where blue is the keyword, and Blue is the colour name.

    There may be an easier way.. but it works for me...

    public partial class MainWindow : Window
    {
      private FlowDocument chatDoc;
    
      public MainWindow()
      {
        InitializeComponent();
    
        chatDoc = new FlowDocument();
        chatDoc.SetValue(Paragraph.LineHeightProperty, 1.0);
      }
    
      protected void DisplayMessage(string message)
      {
        try
        {
          this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
          new UpdatePublicChatDelegate(UpdateChat), message);
        }
        catch (Exception e)
        {
          Console.WriteLine(e.TargetSite.Name);
          Console.WriteLine(e.Message);
        }
      }
    
      public void UpdateChat(string text)
      {
        chatDoc.Blocks.Add(ChatDocument.CreateChatDocument(text));
    
        this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
        new UpdateChatDocDelegate(UpdateChatDoc));
      }
    
      public void UpdateChatDoc()
      {
        try
        {
          chatTextBox.Document = chatDoc;
          chatTextBox.ScrollToEnd();
        }
        catch (Exception e)
        {
          Console.WriteLine(e.Message);
          throw;
        }
      }
    }
    
    public class ChatDocument
    {
      public static Paragraph CreateChatDocument(string text)
      {
        Paragraph para = new Paragraph();
        
        para.Inlines.Add(CreateChatRun(text));
        
        ReplaceKeywords(ref para);
        
        return para;
      }
      
      public static Run CreateChatRun(string text)
      {
        try
        {
          Color runColour = ClientSettings.Appearance.MessageText.Colour;
          Run chatRun = new Run(text);
          chatRun.Foreground = new SolidColorBrush(runColour);
          return chatRun;
        }
        catch (Exception e)
        {
          Console.WriteLine(e.Message);
        }
        return null;
      }
      
      public static void ReplaceKeywords(ref Paragraph para)
      {
        try
        {
          TextRange tr;
          string xamlString = TextRangeToXamlString(para, out tr);
    
          string curKeyword = string.empty;
          System.Text.RegularExpressions.MatchEvaluator CatchRun = delegate(System.Text.RegularExpressions.Match m)
          {
            string prepend = "";
            string append = "";
            if (m.Groups["prepend"].Length != 0)
            {
              prepend = m.Groups["prepend"].Value + "</Run>";
            }
            if (m.Groups["append"].Length != 0)
            {
              append = "<Run>" + m.Groups["append"].Value;
            }
    
            return String.Format("{0}<Run Foreground=\"" + ClientSettings.Keywords[curKeyword].ToString() + "\">{1}</Run>{2}", prepend, curKeyWord, append);
          };
    
          int replacementStartPos = xamlString.IndexOf("<Run>");
          foreach (KeyValuePair<string, Color> keyword in ClientSettings.Keywords)
          {
            curKeyword = keyword.Key;
            string regexMatch = @"(?<prepend>.*)" + System.Text.RegularExpressions.Regex.Escape(keyword.Key) + "(?<append>.*)";
            System.Text.RegularExpressions.Regex findLocalNick = new System.Text.RegularExpressions.Regex(regexMatch, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            xamlString = findLocalNick.Replace(xamlString, CatchRun, 1000, replacementStartPos);
          }
          xamlString = xamlString.Replace("<Run></Run>", "");
          XamlStringToTextRange(ref tr, xamlString);
        }
        catch (Exception e)
        {
          Console.WriteLine(e.Message);
        }
      }
      
      private static string TextRangeToXamlString(Paragraph para, out TextRange tr)
      {
        tr = new TextRange(para.ContentStart, para.ContentEnd);
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        tr.Save(ms, DataFormats.Xaml);
        return Encoding.UTF8.GetString(ms.ToArray());
      }
            
      private static void XamlStringToTextRange(ref TextRange tr, string xamlString)
      {
        System.IO.MemoryStream msOut = new System.IO.MemoryStream();
        System.IO.StreamWriter sw = new System.IO.StreamWriter(msOut);
        sw.Write(xamlString);
        sw.Flush();
        msOut.Seek(0, System.IO.SeekOrigin.Begin);
        tr.Load(msOut, DataFormats.Xaml);
      }
    }
    
  • Saturday, November 07, 2009 6:51 AMRikz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Thanks for replying bt m not familiar with C#.
    I converted the code to VB.Net but its dificult for me to simulate..

    I will explain my requirment once more.

    my application is in WPF(VB.NET)

    I will be having one list of Names(lstOfNames)

    wen my screen gets displayed i will be havin one paragraph inside the RICHTEXTBOX(System.Windows.Controls.RichTextBox)
    <RichTextBox Height="50" Name="rtb" Width="212" Margin="139,37,127,37" />

    Now wat i need to do is if paragraph contains any name dat is in lstOfNames as well then change its fontstyle(either color/background) & then display it in RICHTEXTBOX

  • Saturday, November 07, 2009 9:07 AMRahul P Nath Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     AnswerHas Code
    Hi,
    Here is a small sample in vb

    <Grid>
            <RichTextBox Height="165" Margin="27,12,62,85" Name="RichTextBox1" Width="189" />
            <Button Height="23" Margin="82,0,121,20" Name="Button1" VerticalAlignment="Bottom">Button</Button>
        </Grid>

    Class Window1
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
            Dim objtextRange As TextRange
            Dim lstWordstoBeMatched As New List(Of String)
            lstWordstoBeMatched.Add("Hello")
            lstWordstoBeMatched.Add("to")
            Dim objWordStartPoint As TextPointer
            Dim objWordEndPoint As TextPointer
    
            objtextRange = New TextRange(RichTextBox1.Document.ContentStart, RichTextBox1.Document.ContentEnd)
            Dim strText As String
            strText = objtextRange.Text
            Dim lstMatchGroup As MatchCollection
            Dim objStart As TextPointer
            objStart = RichTextBox1.Document.ContentStart
            For Each strMatch In lstWordstoBeMatched
                lstMatchGroup = Regex.Matches(strText, strMatch)
                For Each objMatch As Match In lstMatchGroup
                    objWordStartPoint = GoToPoint(objStart, objMatch.Index)
                    objWordEndPoint = GoToPoint(objStart, objMatch.Index + objMatch.Length)
                    objtextRange = New TextRange(objWordStartPoint, objWordEndPoint)
                    objtextRange.ApplyPropertyValue(TextElement.FontWeightProperty, FontWeights.Bold)
                Next
            Next
    
        End Sub
    
        Private Sub Window1_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
            RichTextBox1.Document.Blocks.Clear()
            Dim obj As New Paragraph
            obj.Inlines.Add("Hello weelcome to the program.Hello how are you.to the message")
            RichTextBox1.Document.Blocks.Add(obj)
        End Sub
    
    
        Public Function GoToPoint(ByVal start As TextPointer, ByVal x As Integer) As TextPointer
            Dim out As TextPointer = start
            Dim i As Integer = 0
            Do While i < x
                If out.GetPointerContext(LogicalDirection.Backward) = TextPointerContext.Text Or _
                     out.GetPointerContext(LogicalDirection.Backward) = TextPointerContext.None Then
                    i += 1
                End If
                If out.GetPositionAtOffset(1, LogicalDirection.Forward) Is Nothing Then
                    Return out
                Else
                    out = out.GetPositionAtOffset(1, LogicalDirection.Forward)
                End If
            Loop
            Return out
        End Function
    
    
    End Class
    Here I am entering the sample text in the code behind and the list of words to be made bold also .
    Whatever is passed in the list will be make bold.

    Hope it helps
    Please mark posts as answers/helpful if it answers your query. This would be helpful for others facing the same kind of problem
    • Marked As Answer byRikz Saturday, November 07, 2009 9:17 AM
    •  
  • Saturday, November 07, 2009 9:25 AMRikz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Tx.! :)
  • Saturday, November 14, 2009 12:01 PMRahul P Nath Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hi,
    See this link too for some help on it

    Hope it helps
    Please mark posts as answers/helpful if it answers your query. This would be helpful for others facing the same kind of problem