Changing character colour from input - c#

I'm trying to change the colour of a character if the input from the text box matches the one in the rich text box.
char key = e.KeyChar;
for(int i = 0; i < rchtxtbox.Text.Length; i++)
{
char currentLetter = rchtxtbox.Text[i];
if (key == currentLetter)
{
rchtxtbox.SelectionStart = 0;
rchtxtbox.SelectionLength = 1;
rchtxtbox.SelectionColor = Color.White;
rchtxtbox.SelectionBackColor = Color.LightGreen;
}
}
It only highlights the current letter if it does matches. An example is if the word in the rich text box is "balloon" and the input first typed is "b", it matches and changes colour but if the next letter was added "ba" the function stops working and does not change colour. Other alternatives I have tried ended up changing the colours of all matched characters. I want to be able to colour it character by character if it matches, is there a way to do this easily?

Ok, here's how you can achieve this. I have used KeyUp event instead of keypress
private void textBox1_KeyUp(object sender, KeyEventArgs e) {
if (textBox1.TextLength == 0) { return; }
int index;
index = textBox1.TextLength - 1;
char key = textBox1.Text[index];
if (rchtxtbox.TextLength > index && rchtxtbox.Text[index] == key) {
if (rchtxtbox.Text[index] == key) {
rchtxtbox.SelectionStart = index;
rchtxtbox.SelectionLength = 1;
rchtxtbox.SelectionColor = Color.White;
rchtxtbox.SelectionBackColor = Color.LightGreen;
}
}
}
Make sure you replace textBox1 above with the name of your textbox

If I am understanding your questions correctly, the issue is just that you are only ever selecting the first character for highlight.
You should be setting SelectionStart to i, so it selects and highlights the character you are comparing against:
rchtxtbox.SelectionStart = i;
Edit:
After thinking about what you're trying to do, I think you have a rich text box with text in it. You also have a text box that the user is typing into. As the user types into the text box, you want to highlight that text in the rich text box. Correct?
Here is a simple example, although this doesn't account for multiple occurrences of the text being found.
private void textBox1_TextChanged(object sender, EventArgs e)
{
int idx = richTextBox1.Text.IndexOf(textBox1.Text);
if (idx > -1)
{
richTextBox1.SelectionStart = idx;
richTextBox1.SelectionLength = textBox1.Text.Length;
richTextBox1.SelectionColor = Color.White;
richTextBox1.SelectionBackColor = Color.LightGreen;
}
}

Related

Why does autocomplete in my Winforms ComboBox change the cursor location when typing?

I have a WinForms ComboBox within an Outlook Add-in which populates the drop-down with user names, when the user types names in the edit box. When the user reaches the third character. The data source of the ComboBox is assigned at this point, and the curser jumps to the beginning of the edit box instead of staying at the end.
The behavior I want is that the cursor stays at the end of the string I am typing, even when the drop-down is populated with more data.
I've tried hacking this with send keys, but it doesn't always work. The code which reads the keys below is in the key pressed event.
private void comboBox1_KeyPress(object sender, KeyEventArgs e)
{
var acceptableKeys = ConfigurationManager.AppSettings["AcceptableKeys"];
if (cmbAssignedTo.Text.Length > 2 && acceptableKeys.Contains(e.KeyCode.ToString().ToUpper()) && e.Modifiers == Keys.None)
{
var request = RestHandler.CreateRequest(ConfigurationManager.AppSettings["ContactsSearchResource"] + cmbAssignedTo.Text.Trim(), Method.GET);
var response = RestHandler.ExecuteRequest(request, ConfigurationManager.AppSettings["myServiceURL"]);
this.cmbAssignedTo.DataSourceChanged -= new System.EventHandler(this.cmbAssignedTo_DataSourceChanged);
//Assign a new data source
DataHandler.UpdateComboboxDataSource(cmbAssignedTo, response.Content);
this.cmbAssignedTo.DataSourceChanged += new System.EventHandler(this.cmbAssignedTo_DataSourceChanged);
}
e.Handled = true;
}
Edit
internal static void UpdateComboboxDataSource(ComboBox cmbAssignedTo, string data)
{
var list = BuildAssignmentList(data);
if ((list.Count() == 0 && cmbAssignedTo.Items.Count == 0) || list.Count() > 0)
{
var savedText = cmbAssignedTo.Text;
cmbAssignedTo.DataSource = list;
cmbAssignedTo.SelectedValue = "";
cmbAssignedTo.Text = savedText;
SendKeys.Send("{end}");
}
if (cmbAssignedTo.Items.Count > 0)
{
cmbAssignedTo.DroppedDown = true;
Cursor.Current = Cursors.Default;
}
}
I don't see how I can update the dropdown without changing the DataSource and that change appears to cause the cursor to jump. Should I try different event than KeyPressed? Is there some other solution I'm missing?
As another hack you can play with ComboBox's SelectionStart property:
int i = comboBox1.SelectionStart;
comboBox1.DataSource = new System.Collections.Generic.List<string>(){"aaaaaa", "bbbbbb", "ccccccc"};
comboBox1.SelectionStart = i;
This code changes the DataSource and retain the cursor position. If you want cursor to be always at end - set SelectionStart to comboBox1.Text.Length.
UPD: To fight against the "first item selection" you may use another hack:
private bool cbLock = false;
private void comboBox1_TextChanged(object sender, EventArgs e)
{
// lock is required, as this event also will occur when changing the selected index
if (cbLock)
return;
cbLock = true;
int i = comboBox1.SelectionStart;
// store the typed string before changing DS
string text = comboBox1.Text.Substring(0, i);
List<string> ds = new System.Collections.Generic.List<string>() { "aaaaaa", "aaabbb", "aaacccc" };
comboBox1.DataSource = ds;
// select first match manually
for (int index = 0; index < ds.Count; index++)
{
string s = ds[index];
if (s.StartsWith(text))
{
comboBox1.SelectedIndex = index;
break;
}
}
// restore cursor position and free the lock
comboBox1.SelectionStart = i;
cbLock = false;
}
When typing "aaab" it selects the "aaabbb" string.

Insert text at specific index with a specific color in a RichTextbox

I want to insert a string in my RichTextbox, at a specific position and with a specific color. So I tried to add an extension for the method AppendText() of the RichTextbox class.
public static void AppendText(this RichTextBox Box, string Text, Color col, int SelectionStart)
{
Box.SelectionStart = SelectionStart;
Box.SelectionLength = 0;
Box.SelectionColor = col;
Box.SelectionBackColor = col;
Box.Text = Box.Text.Insert(SelectionStart, Text);
Box.SelectionColor = Box.ForeColor;
}
I tried to use this in a class called RichTextBoxExtension. The result is not as per my expectation. The string is inserted but not with the color selected.
Is there any better way to do this functionality?
EDIT: I think it could be interesting to inform you why I need this functionality. Actually, when user write a closing parenthesis, I would like to highligh (or color) the associative opening parenthesis.
so for example if the user write (Mytext), the first parenthesis will be in color when user tapped ")" and keep the selection on this parenthesis.
You have to use the SelectedText property of the RichTextBox control. Also make sure to keep track of the values of the current selection before you change anything.
Your code should look like this (I give away what Hans was hinting at) :
public static void AppendText(this RichTextBox Box,
string Text,
Color col,
int SelectionStart)
{
// keep all values that will change
var oldStart = Box.SelectionStart;
var oldLen = Box.SelectionLength;
//
Box.SelectionStart = SelectionStart;
Box.SelectionLength = 0;
Box.SelectionColor = col;
// Or do you want to "hide" the text? White on White?
// Box.SelectionBackColor = col;
// set the selection to the text to be inserted
Box.SelectedText = Text;
// restore the values
// make sure to correct the start if the text
// is inserted before the oldStart
Box.SelectionStart = oldStart < SelectionStart ? oldStart : oldStart + Text.Length;
// overlap?
var oldEnd = oldStart + oldLen;
var selEnd = SelectionStart + Text.Length;
Box.SelectionLength = (oldStart < SelectionStart && oldEnd > selEnd) ? oldLen + Text.Length : oldLen;
}

Resize font if text doesnt fit into cell (XRTable)

How to resize cell content (font size) if it doesn't fit. I don't want word-wrap or change cell's size since the form has to fit on single page. The text might have various lengths. It might contain spaces but doesn't have to.
#edit
I've made a mistake. The control I meant is not a XtraGrid but XRTable.
I suggest you to look at the Appearances at first. There are multiple ways to customize appearances of individual rows and cells.
If these options are not helpful, you can manually draw cell content as you needed using the Custom Drawing feature. For example, you can use the GridView.CustomDrawCell event to check whether or not the cell's content is exceed the cell's bounds and update the font of this cell accordingly.
Related example: How to: Custom Draw Cells Depending Upon Cell Values
You can change the font of the cell where the text flows as follows
private void gvView_CustomDrawCell(object sender, DevExpress.XtraGrid.Views.Base.RowCellCustomDrawEventArgs e)
{
if (e.Column != null && e.Column.Name == bgcStav.Name)
{
float minFontSize = 6;
string text = "teeeeeeeeeeeeeext";
int minWidth = gvView.CalcColumnBestWidth(bgcStav);
SizeF s = e.Appearance.CalcTextSize(e.Graphics, text, minWidth);
if (s.Width >= minWidth)
{
e.Appearance.Font = new Font(e.Appearance.Font.FontFamily, minFontSize);
}
}
}
but it is much better to trim the text if it overflows (you do not know how long the text can be), when you do not want to use wordwrap
private void gvView_CustomDrawCell(object sender, DevExpress.XtraGrid.Views.Base.RowCellCustomDrawEventArgs e)
{
if (e.Column != null && e.Column.Name == bgcStav.Name)
{
string text = e.DisplayText;
string newText = "";
int maxWidth = e.Bounds.Width - 20;
SizeF textSize =e.Graphics.MeasureString(text, e.Appearance.Font);
if (textSize.Width >= maxWidth)
{
string textPom = "";
for (int i = 0; i < text.Length; i++)
{
textPom = text.Substring(0, i) + "...";
textSize = e.Graphics.MeasureString(textPom, e.Appearance.Font);
if (textSize.Width >= maxWidth)
{
newText = text.Substring(0, i - 1) + "...";
break;
}
}
e.DisplayText = newText;
}
}
}
Advantage of this solution is that the crop only what is displaied, but in the datatable text remains in its original form

Color specific words in RichtextBox

How can I make, that when the user types specific words like 'while' or 'if' in a rich textbox, the words will color purple without any problems? I've tried diffrent codes, but none of them were usable. The codes were like below:
if (richTextBox.Text.Contains("while"))
{
richTextBox.Select(richTextBox.Text.IndexOf("while"), "while".Length);
richTextBox.SelectionColor = Color.Aqua;
}
Also, I want that when the user removes the word or removes a letter from the word, the word will color back to its default color. I'm making a program with a code editor in it.
I am using Visual c#.
Thank you.
Add an event to your rich box text changed,
private void Rchtxt_TextChanged(object sender, EventArgs e)
{
this.CheckKeyword("while", Color.Purple, 0);
this.CheckKeyword("if", Color.Green, 0);
}
private void CheckKeyword(string word, Color color, int startIndex)
{
if (this.Rchtxt.Text.Contains(word))
{
int index = -1;
int selectStart = this.Rchtxt.SelectionStart;
while ((index = this.Rchtxt.Text.IndexOf(word, (index + 1))) != -1)
{
this.Rchtxt.Select((index + startIndex), word.Length);
this.Rchtxt.SelectionColor = color;
this.Rchtxt.Select(selectStart, 0);
this.Rchtxt.SelectionColor = Color.Black;
}
}
}
This is something that you can do, I would recommend using a regular expression to find all matches of the word in case it occurs many times. Also keep in mind that the string find could be a list of strings out side of a for loop to consider multiple words but this should get you started.
//dont foget to use this at the top of the page
using System.Text.RegularExpressions;
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
string find = "while";
if (richTextBox1.Text.Contains(find))
{
var matchString = Regex.Escape(find);
foreach (Match match in Regex.Matches(richTextBox1.Text, matchString))
{
richTextBox1.Select(match.Index, find.Length);
richTextBox1.SelectionColor = Color.Aqua;
richTextBox1.Select(richTextBox1.TextLength, 0);
richTextBox1.SelectionColor = richTextBox1.ForeColor;
};
}
}
You can use richTextBox1_KeyDown event
private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Space)
{
String abc = this.richTextBox1.Text.Split(' ').Last();
if (abc == "while")
{
int stIndex = 0;
stIndex = richTextBox1.Find(abc, stIndex, RichTextBoxFinds.MatchCase);
richTextBox1.Select(stIndex, abc.Length);
richTextBox1.SelectionColor = Color.Aqua;
richTextBox1.Select(richTextBox1.TextLength, 0);
richTextBox1.SelectionColor = richTextBox1.ForeColor;
}
}
}
If instead of a word you want to highlight a regular expression, you can use this:
private void ColorizePattern(string pattern, Color color)
{
int selectStart = this.textBoxSrc.SelectionStart;
foreach (Match match in Regex.Matches(textBoxSrc.Text, pattern))
{
textBoxSrc.Select(match.Index, match.Length);
textBoxSrc.SelectionColor = color;
textBoxSrc.Select(selectStart, 0);
textBoxSrc.SelectionColor = textBoxSrc.ForeColor;
};
}

Formatting first line of RichTextBox with capital letters and bold

If I have a RichTextBox and want output like the first line is a font with capital letters and bold, while the next line on the contrary, what should I do?
output like this:
MY NAME IS
Diana
My address is
China
Hey try this, it works, but you might see the text flicker for a second if the user types really fast, like holding down "Enter" and etc.
private void Form_Load(object sender, EventArgs e)
{
// append the function to the RichTextBox's TextChanged event
MyRichTextBox.TextChanged += Capitalize_Bold_FirstLine;
}
private void Capitalize_Bold_FirstLine(object sender, EventArgs e)
{
RichTextBox box = sender as RichTextBox;
if (box != null && box.Text != "")
{
// get the current selection text of the textbox
int ss = box.SelectionStart;
int sl = box.SelectionLength;
// get the position where the first line ends
int firstLineEnd = box.Text.IndexOf('\n');
if (firstLineEnd < 0)
firstLineEnd = box.Text.Length;
// split the lines
string[] lines = box.Text.Split('\n');
// capitalize the first line
lines[0] = lines[0].ToUpper();
// join them back and set the new text
box.Text = String.Join("\n", lines);
// select the first line and make it bold
box.SelectionStart = 0;
box.SelectionLength = firstLineEnd;
box.SelectionFont = new Font(box.Font, FontStyle.Bold);
// select the rest and make it regular
box.SelectionStart = firstLineEnd;
box.SelectionLength = box.Text.Length - firstLineEnd;
box.SelectionFont = new Font(box.Font, FontStyle.Regular);
// go back to what the user had selected
box.SelectionStart = ss;
box.SelectionLength = sl;
}
}

Categories