LearningWPFrn
LearningWPFrn

Reputation: 55

Change Color of each word that starts with specific letter

I'm working in my getter just as a place to test this, but essentially what I'm trying to accomplish is while the users is typing for every instance of 'D' as the first letter of a word change the color of that text to red. The color change is accomplished by bounding the Foreground of a RichTextBox to my Customers.TColor property.
My real logic issues are happening in my TColor property as the program worked when getter was just single line(now commented out) looking for just the first character of Character.Name:
return name.Length > 0 && name[0] == 'D' ? Brushes.Red : Brushes.Black;
However, I'm trying to extend this functionality to every word. Here is my TColor property logic:

 public Brush TColor
    {
        get
        {
            string[] allNames = name.Split(null);
            foreach (string n in allNames)
            {
                if(n[0] == 'D')
                {
                    return Brushes.Red;
                }
                else
                {
                    return Brushes.Black;
                }
            }
            return Brushes.Black;
            //return name.Length > 0 && name[0] == 'D' ? Brushes.Red : Brushes.Black;
        }
        set
        {
            tColor = defaultColor;
        }
    } 

What I'm trying to do is get each word individually, so allNames should be splitting the user input into single words then looks at the first char in each of those if it's a D set the brush to red otherwise set the brush for that word to black. If I backspace out of my default values that is set at construction of a Customer object I get a runtime error.
I'm wondering two things
1. if this is the way I should be trying to change the color of an individual word in a RichTextBody.
2. How can I effectively look at the first character of each word and change its color.
Here is what my RichTextBody Currently looks like:

<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Center" Margin="10,0,3.4,0" Width="505">
    <Label Content="Customer name:" />
    <RichTextBox x:Name="richTextBox" Height="100" Width="366">
        <FlowDocument>
            <Paragraph Foreground="{Binding Customer.TColor}">
                <Run></Run>
                <Run Text="{Binding Customer.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" />
            </Paragraph>
        </FlowDocument>
    </RichTextBox>
    <Button Content="Update" Command="{Binding UpdateCommand}"/>
</StackPanel>

My relevant variables and properties are as follows:

private string name;
private Brush tColor;
private Brush defaultColor = Brushes.Black;

My constructor is:

public Customer(String customerName)
    {
        Name  = customerName;
        TColor = defaultColor;
    }

My Name property is:

public String Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TColor"));
            //OnPropertyChanged("Name");
        }
    }

Just in case I left anything out, a repo of the project is here

Upvotes: 2

Views: 1077

Answers (1)

Walt Ritscher
Walt Ritscher

Reputation: 7047

This example uses the TextChanged handler to format words in a RichTextBox. It'll need to be adapted to your implementation.

XAML

<Grid>
  <RichTextBox x:Name="RichTextBox1" />
</Grid>

Code

public ColorizeWordWindow() {
      InitializeComponent();
      this.RichTextBox1.TextChanged += RichTextBox_TextChanged;
}

    private void RichTextBox_TextChanged(object sender, TextChangedEventArgs e) {
      RichTextBox1.TextChanged -= RichTextBox_TextChanged;
      int position = RichTextBox1.CaretPosition.
                      GetOffsetToPosition(RichTextBox1.Document.ContentEnd);

      foreach (Paragraph para in RichTextBox1.Document.Blocks.ToList())
      {
        string text = new TextRange(para.ContentStart, para.ContentEnd).Text;

        para.Inlines.Clear();

        // using space as word delimiter assumes en-US for locale
        // other locales (Korean, Thai, etc. ) will need adjustment

        var words = text.Split(' ');
        int count = 1;

        foreach (string word in words)
        {
          if (word.StartsWith("D"))
          {
            var run = new Run(word);

            run.Foreground = new SolidColorBrush(Colors.Red);
            run.FontWeight = FontWeights.Bold;
            para.Inlines.Add(run);
          }
          else
          {
            para.Inlines.Add(word);
          }

          if (count++ != words.Length)
          {
            para.Inlines.Add(" ");
          }
        }
      }

      RichTextBox1.CaretPosition = RichTextBox1.Document.ContentEnd.
                                     GetPositionAtOffset(-position);
      RichTextBox1.TextChanged += RichTextBox_TextChanged;
    }

Result

Screenshot

Upvotes: 1

Related Questions