Numbered list on Richtextbox - c#

I'm trying to add numbered list functionality to a text editor. RichTextbox already provides the SelectionBullet property to change a selection to a bulleted list. But i was unable to find a similar property to generate numbered list. Is there any standard way to create a numbered list on Richtextbox. If not, i would have to implement it myself so code snips that could help me do that will help, Thank you.

I know that a link is not gernerally accepted as a good answer, however the article RichTextBox with Search Line Numbering, Bulleting, Printing, Searching Support on CodeProject could probably help you out quite a bit with what you are looking for.
In this article, the author extends the RichTextBox control into something that can do what you are asking (and more), plus the code is posted there for all to see.

Well, i implemented it as follows.
private void btnNumbers_Click(object sender, EventArgs e)
{
string temptext = rtbMain.SelectedText;
int SelectionStart = rtbMain.SelectionStart;
int SelectionLength = rtbMain.SelectionLength;
rtbMain.SelectionStart = rtbMain.GetFirstCharIndexOfCurrentLine();
rtbMain.SelectionLength = 0;
rtbMain.SelectedText = "1. ";
int j = 2;
for( int i = SelectionStart; i < SelectionStart + SelectionLength; i++)
if (rtbMain.Text[i] == '\n')
{
rtbMain.SelectionStart = i + 1;
rtbMain.SelectionLength = 0;
rtbMain.SelectedText = j.ToString() + ". ";
j++;
SelectionLength += 3;
}
}
private void rtbMain_KeyDown(object sender, KeyEventArgs e)
{//this piece of code automatically increments the bulleted list when user //presses Enter key
int tempNum;
if (e.KeyCode == Keys.Enter)
try
{
if (char.IsDigit(rtbMain.Text[rtbMain.GetFirstCharIndexOfCurrentLine()]))
{
if (char.IsDigit(rtbMain.Text[rtbMain.GetFirstCharIndexOfCurrentLine() + 1]) && rtbMain.Text[rtbMain.GetFirstCharIndexOfCurrentLine() + 2] == '.')
tempNum = int.Parse(rtbMain.Text.Substring(rtbMain.GetFirstCharIndexOfCurrentLine(),2));
else tempNum = int.Parse(rtbMain.Text[rtbMain.GetFirstCharIndexOfCurrentLine()].ToString());
if (rtbMain.Text[rtbMain.GetFirstCharIndexOfCurrentLine() + 1] == '.' || (char.IsDigit(rtbMain.Text[rtbMain.GetFirstCharIndexOfCurrentLine() + 1]) && rtbMain.Text[rtbMain.GetFirstCharIndexOfCurrentLine() + 2] == '.'))
{
tempNum++;
rtbMain.SelectedText = "\r\n" + tempNum.ToString() + ". ";
e.SuppressKeyPress = true;
}
}
}
catch{}
}

Here is my answer... which is easily readable and refineable. I took a much different approach but added the ability to remove the numbered list within the selection if it already exists. Please note that so far I have only lightly tested it and it seems to work good... but it may need further refinement.
private void btnOrdered_Click(object sender, EventArgs e)
{
string[] splitSelection = null;
// If selection split selection else split everything
if (this.txtCaptionEditor.SelectionLength > 0)
{
splitSelection = this.txtCaptionEditor.SelectedText.Replace("\r\n", "\n").Split("\n".ToCharArray());
}
else
{
splitSelection = this.txtCaptionEditor.Text.Replace("\r\n", "\n").Split("\n".ToCharArray());
}
bool Exists = false;
for (int i = 0; i < splitSelection.GetLength(0); i++)
{
// If Ordered List Allready exists in selection then remove else add
if (!string.IsNullOrEmpty(splitSelection[i]))
{
if (splitSelection[i].Substring(0, 2) == "1.") { Exists = true; }
}
}
for (int i = 0; i < splitSelection.GetLength(0); i++)
{
int lineCount = (i + 1);
if (Exists)
{
this.txtCaptionEditor.Text = this.txtCaptionEditor.Text.Replace(Convert.ToString(lineCount) + ". ", "");
}
else
{
if(!string.IsNullOrEmpty(splitSelection[i]))
{
this.txtCaptionEditor.Text = this.txtCaptionEditor.Text.Replace(splitSelection[i], Convert.ToString(lineCount) + ". " + splitSelection[i]);
}
}
}
}
private void txtCaptionEditor_KeyDown(object sender, KeyEventArgs e)
{
string[] splitSelection = this.txtCaptionEditor.Text.Replace("\r\n", "\n").Split("\n".ToCharArray());
if (e.KeyCode == Keys.Enter)
{
// Get Current Line Position
int currentLine = this.txtCaptionEditor.GetLineFromCharIndex(this.txtCaptionEditor.SelectionStart);
// Only Run if the previous line is greater than zero
if ((currentLine) >= 0)
{
// Loop through 100 possible numbers for match you can go higher
// If you think your numbered list could go above 100
for (int i = 0; i < 100; i++)
{
if (splitSelection[(currentLine)].Substring(0, 2) == Convert.ToString((i + 1)) + ".")
{
// If the substring of the current line equals a numbered list value.. enumerate next line
this.txtCaptionEditor.SelectedText = "\n" + (i + 2) + ". ";
e.SuppressKeyPress = true;
}
}
}
}
}

Related

code doesn't always highlight the selected text in a richtextbox

richTextBox1 contains text
I click on a word and Console displays that word for me and it highlights/selects the word i clicked on.
To do this, I keep the index of the character I clicked on then go left and right until I hit a space, -1, or end of file. Now I have the indexes of the beginning and end of the word. The last two lines are supposed to select the word between those two indexes.
However, what happens is that sometimes it highlights the word I want and sometimes it highlights all the words to the right of the character I clicked on.
"omar hello where are you going"
If I click on h in hello, it highlights hello where instead of highlighting hello
If I click on o in going, it will highlight going only as it should
If I click on o in you, it will highlight you going
I used console to check the start and end indexes of the word and they're always right yet for some reason, other words are selected in addition to the word i clicked on
private void richTextBox1_Click(object sender, EventArgs e)
{
int length = richTextBox1.Text.Length;
int rightPart = richTextBox1.SelectionStart;
int leftPart = richTextBox1.SelectionStart - 1;
string rightText = "";
string leftText = "";
while (rightPart != length)
{
if (richTextBox1.Text[rightPart].ToString().CompareTo(" ") != 0)
{
rightText += richTextBox1.Text[rightPart];
rightPart++;
}
else
{
break;
}
}
while (leftPart != -1)
{
if (richTextBox1.Text[leftPart].ToString().CompareTo(" ") != 0)
{
leftText = richTextBox1.Text[leftPart] + leftText;
leftPart--;
}
else
{
break;
}
}
leftPart++;
Console.WriteLine("\nSelected word is " + leftText + rightText + "\n");
richTextBox1.SelectionStart = leftPart;
richTextBox1.SelectionLength = rightPart;
}
The problem appears to be that you are setting the SelectionLength equal to rightPart. Remember this property represents the length of the selection, not the last index of the selection.
Instead, try changing your code to calculate the length by getting the difference between leftPart and rightPart:
richTextBox1.SelectionLength = rightPart - leftPart;
For what it's worth, your code can be shortened a little:
private void richTextBox1_Click(object sender, EventArgs e)
{
if (richTextBox1.TextLength == 0) return;
int rightPart = richTextBox1.SelectionStart;
int leftPart = richTextBox1.SelectionStart - 1;
while (rightPart < richTextBox1.TextLength && richTextBox1.Text[rightPart] != ' ')
{
rightPart++;
}
while (leftPart > -1 && richTextBox1.Text[leftPart] != ' ')
{
leftPart--;
}
leftPart++;
Console.WriteLine($"\nSelected word is " +
richTextBox1.Text.Substring(leftPart, rightPart - leftPart) + "\n");
richTextBox1.SelectionStart = leftPart;
richTextBox1.SelectionLength = rightPart - leftPart;
}
Or even a little more, using IndexOf and LastIndexOf instead of loops to find the spaces:
private void richTextBox1_Click(object sender, EventArgs e)
{
if (richTextBox1.TextLength == 0) return;
// Find the space before this word and after this word
var selStart = Math.Min(richTextBox1.SelectionStart, richTextBox1.TextLength - 1);
var firstSpace = richTextBox1.Text.LastIndexOf(' ', selStart);
var lastSpace = richTextBox1.Text.IndexOf(' ', selStart);
var start = firstSpace + 1;
var length = (lastSpace < 0 ? richTextBox1.TextLength : lastSpace) - start;
Console.WriteLine($"\nSelected word is {richTextBox1.Text.Substring(start, length)} \n");
richTextBox1.SelectionStart = start;
richTextBox1.SelectionLength = length;
}

Making a picture box become visible / invisible on a certain integer? (C#)

I was wondering how I would make a picture box become invisible or visible when a certain integer matches.
My program revolves around 2 players going around a board, and when they add there 2 Di up, they will move the amount of spaces.
My problem being, My friend and I have no idea what is wrong with the current code we have, it throws no errors which baffles him, especially myself.
I've made it so my program add's the Di up on every roll, and add's it to the integer.
Anyone have any idea's on whats wrong? If not, a better approach?
Code
private void SelectPos(PictureBox pic)
{
PictureBox[] numbers = { P1_1, P1_2, P1_3, P1_4, P1_5, P1_6, P1_7, P1_8, P1_9, P1_10, P1_11, P1_12, P1_13, P1_14, P1_15, P1_16, P1_17, P1_18, P1_19, P1_20, P1_21, P1_22, P1_23, P1_24, P1_25, P1_26, P1_27, P1_28, P1_29, P1_30, P1_31, P1_32, P1_33, P1_34, P1_35, P1_36, P1_37, P1_38, P1_39, P1_40, P1_41, P1_42, P1_43, P1_44, P1_45, P1_46, P1_47, P1_48, P1_49 };
for (int i = 0; i < numbers.Length; i++)
{
if (pic == numbers[i])
{
numbers[i].Visible = true;
MessageBox.Show("k");
}
{
numbers[i].Visible = false;
MessageBox.Show("l");
}
}
}
private void bunifuFlatButton1_Click(object sender, EventArgs e)
{
Roll();
System.Threading.Thread.Sleep(100);
Roll2();
Goes_Num.Text = (int.Parse(Goes_Num.Text) + 1).ToString();
if (Convert.ToInt32(Goes_Num.Text) % 2 == 0)
{
WhichPlayer.Text = "Player 2";
P2_Number.Text = (int.Parse(P2_Number.Text) + 1).ToString();
int p2Int = Convert.ToInt32(P2_Pos.Text);
P2_Pos.Text = (p2Int + dice + dice2).ToString();
}
else if (Convert.ToInt32(Goes_Num.Text) % 2 != 0)
{
WhichPlayer.Text = "Player 1";
P1_Number.Text = (int.Parse(P1_Number.Text) + 1).ToString();
int p1Int = Convert.ToInt32(P1_Pos.Text);
P1_Pos.Text = (p1Int + dice + dice2).ToString();
int P1 = (Convert.ToInt32(P1_Pos.Text));
SelectPos(P1_1);
/*switch (P1)
{
case 1:
P1_1.Visible = true;
break;
case 2:
P1_2.Visible = true;
break;
}*/
/*String[] hi = { "1", "2" };
for (int i = 0; i < hi.Length; i++)
{
var visible = p1
if(visible == hi[i])
{
hi[i].Visible = true;
}
else
{
hi[i].Visible = false;
}
}*/
}
}
(P1-1 all the way to P1-49 are images)
Thanks,
James
It looks like you're trying to pass an int to your SelectPos function but it expects a PictureBox. You could fix this doing something similar to the following:
private void SelectPos(int pic)
{
PictureBox[] numbers = { P1_1, P1_2, P1_3, P1_4, P1_5, P1_6, P1_7, P1_8, P1_9, P1_10, P1_11, P1_12, P1_13, P1_14, P1_15, P1_16, P1_17, P1_18, P1_19, P1_20, P1_21, P1_22, P1_23, P1_24, P1_25, P1_26, P1_27, P1_28, P1_29, P1_30, P1_31, P1_32, P1_33, P1_34, P1_35, P1_36, P1_37, P1_38, P1_39, P1_40, P1_41, P1_42, P1_43, P1_44, P1_45, P1_46, P1_47, P1_48, P1_49 };
//Set all picture boxes to be not visible
for (int i = 0; i < numbers.Length; i++)
{
numbers[i].Visible = false;
}
//Set the picture at the given index to visible
numbers[pic].Visible = true;
}
private void bunifuFlatButton1_Click(object sender, EventArgs e)
{
Roll();
System.Threading.Thread.Sleep(100);
Roll2();
Goes_Num.Text = (int.Parse(Goes_Num.Text) + 1).ToString();
if (Convert.ToInt32(Goes_Num.Text) % 2 == 0)
{
WhichPlayer.Text = "Player 2";
P2_Number.Text = (int.Parse(P2_Number.Text) + 1).ToString();
int p2Int = Convert.ToInt32(P2_Pos.Text);
P2_Pos.Text = (p2Int + dice + dice2).ToString();
}
else if (Convert.ToInt32(Goes_Num.Text) % 2 != 0)
{
WhichPlayer.Text = "Player 1";
P1_Number.Text = (int.Parse(P1_Number.Text) + 1).ToString();
int p1Int = Convert.ToInt32(P1_Pos.Text);
P1_Pos.Text = (p1Int + dice + dice2).ToString();
int P1 = (Convert.ToInt32(P1_Pos.Text));
SelectPos(P1);
}
}
You may have to manipulate the value of pic so that it is within the bounds of the array (0-48). For example if pic is between 1 and 49 you would need to subtract 1: numbers[pic-1]. Without seeing your whole program I can't tell you exactly how that part of the code would look but it should be pretty easy to figure out. If you aren't familiar with arrays and indexing check out this link or just Google C# Arrays.
As a side note it would be better to the numbers array as a private member of the class this code is in. Unless the values in the array change there's no point in building the array every time the method is called.
Complete code:
private void SelectPos(int pic)
{
PictureBox[] numbers = { P1_1, P1_2, P1_3, P1_4, P1_5, P1_6, P1_7, P1_8, P1_9, P1_10, P1_11, P1_12, P1_13, P1_14, P1_15, P1_16, P1_17, P1_18, P1_19, P1_20, P1_21, P1_22, P1_23, P1_24, P1_25, P1_26, P1_27, P1_28, P1_29, P1_30, P1_31, P1_32, P1_33, P1_34, P1_35, P1_36, P1_37, P1_38, P1_39, P1_40, P1_41, P1_42, P1_43, P1_44, P1_45, P1_46, P1_47, P1_48, P1_49 };
//Set all picture boxes to be not visible
for (int i = 0; i < numbers.Length; i++)
{
numbers[i].Visible = false;
}
//Set the picture at the given index to visible
numbers[pic].Visible = true;
}
private void SelectPos2(int pic2)
{
PictureBox[] numbers2 = { P2_1, P2_2, P2_3, P2_4, P2_5, P2_6, P2_7, P2_8, P2_9, P2_10, P2_11, P2_12, P2_13, P2_14, P2_15, P2_16, P2_17, P2_18, P2_19, P2_20, P2_21, P2_22, P2_23, P2_24, P2_25, P2_26, P2_27, P2_28, P2_29, P2_30, P2_31, P2_32, P2_33, P2_34, P2_35, P2_36, P2_37, P2_38, P2_39, P2_40, P2_41, P2_42, P2_43, P2_44, P2_45, P2_46, P2_47, P2_48, P2_49 };
//Set all picture boxes to be not visible
for (int i = 0; i < numbers2.Length; i++)
{
numbers2[i].Visible = false;
}
//Set the picture at the given index to visible
numbers2[pic2].Visible = true;
}
private void bunifuFlatButton1_Click(object sender, EventArgs e)
{
Roll();
System.Threading.Thread.Sleep(100);
Roll2();
Goes_Num.Text = (int.Parse(Goes_Num.Text) + 1).ToString();
if (Convert.ToInt32(Goes_Num.Text) % 2 == 0)
{
WhichPlayer.Text = "Player 2";
P2_Number.Text = (int.Parse(P2_Number.Text) + 1).ToString();
int p2Int = Convert.ToInt32(P2_Pos.Text);
P2_Pos.Text = (p2Int + dice + dice2).ToString();
int P2 = (Convert.ToInt32(P2_Pos.Text));
SelectPos2(P2);
}
else if (Convert.ToInt32(Goes_Num.Text) % 2 != 0)
{
WhichPlayer.Text = "Player 1";
P1_Number.Text = (int.Parse(P1_Number.Text) + 1).ToString();
int p1Int = Convert.ToInt32(P1_Pos.Text);
P1_Pos.Text = (p1Int + dice + dice2).ToString();
int P1 = (Convert.ToInt32(P1_Pos.Text));
SelectPos(P1);
}
}

I want make a text box area that automatically cuts a long paragraph

text box area that automatically cuts a long paragraph text into 30 characters sentences
i am trying run this code but occurs exception [exception of type 'System.StackOverflowException']
private void txtCutParagraph_TextChanged(object sender, EventArgs e)
{
int limitNum = 30;
string sentence = txtCutParagraph.Text;
string[] words = sentence.Split(' ');
string line = "";
foreach (string word in words)
{
if ((line + word).Length > limitNum)
{
newLine += line + "\r\n";
line = "";
}
line += word + " ";
}
if (line.Length > 0)
newLine += line + "\r\n";
txtCutParagraph.Text = newLine;
}
If the form is freezing is because that txtCutParagraph_TextChanged event is firing infinitely, because you are changing the text of textbox at the end of the event: txtCutParagraph.Text = newLine;, so it means that change text in the textbox, and the event will fire again and again.
To prevent this form from freezing please move your code to another event of textbox, named KeyPress as:
private void txtCutParagraph_KeyPress(object sender, KeyPressEventArgs e)
{
int limitNum = 30;
string sentence = txtCutParagraph.Text;
string[] words = sentence.Split(' ');
string line = "";
foreach (string word in words)
{
if ((line + word).Length > limitNum)
{
newLine += line + "\r\n";
line = "";
}
line += word + " ";
}
if (line.Length > 0)
newLine += line + "\r\n";
txtCutParagraph.Text = newLine;
}
What you are trying to do is called Word wrapping. TextBox class has Wordwrap option by default. unfortunately you cant limit number of characters per line.
You have to write an algorithm instead. I have noticed that your algorithm does not work correctly. so i decided to write one my self (as it was a good practice!). It is hard to handle all situations that can happen inside text formatting. I tried my best anyway you have to write one your self if you are not satisfied with results.
Before using this algorithm you have to disable Wordwrap feature of Textbox. So they will not Interfere each other. In InitializeComponent inside Form Designer add this line.
this.textBox1.WordWrap = false;
Now use this algorithm to do it for you! Note that textbox1 is a multi line text box.
private StringBuilder stringBuilder = new StringBuilder();
private bool _isInsideTextChanged = false;
private const int MaximumChars = 30; // Maximum characters
private StringBuilder WrapText(StringBuilder text, ref int position)
{
StringBuilder newStringBuilder = new StringBuilder(text.ToString());
int charsPerLine = 0;
int lastSpace = -1; // index of last space per line
for (int i = 0; i < newStringBuilder.Length; i++)
{
if (newStringBuilder[i] == ' ')
{
if (newStringBuilder.Length > i + 2 && newStringBuilder.ToString(i + 1, 2) == "\r\n")
{
if (newStringBuilder.Length > i + 3)
{
int next = newStringBuilder.ToString().IndexOf(' ', i + 3);
if (next != -1 && charsPerLine + next - i <= MaximumChars || charsPerLine + newStringBuilder.Length - i - 2 <= MaximumChars)
{
newStringBuilder.Remove(i + 1, 2);
if (i <= textBox1.SelectionStart)
{
position -= 2;
}
continue;
}
}
i++;
continue;
}
if (newStringBuilder.Length > i + 1 && newStringBuilder[i + 1] != ' ')
{
lastSpace = i;
}
}
if (newStringBuilder[i] == '\n' || newStringBuilder[i] == '\r')
{
lastSpace = -1;
charsPerLine = 0;
}
if (++charsPerLine > MaximumChars && lastSpace != -1)
{
newStringBuilder.Insert(lastSpace + 1, "\r\n");
if (lastSpace <= textBox1.SelectionStart)
{
position += 2;
}
charsPerLine = i - lastSpace;
lastSpace = -1;
i++;
}
}
return newStringBuilder;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (_isInsideTextChanged) return;
_isInsideTextChanged = true;
stringBuilder.Clear();
stringBuilder.Append(textBox1.Text);
int position = textBox1.SelectionStart;
string newText = WrapText(stringBuilder, ref position).ToString();
textBox1.Text = newText;
textBox1.SelectionStart = position;
_isInsideTextChanged = false;
}
Here is the test that shows the results.
How this wroks?
This algorithm will count the number of characters from last line break index (default value is 0) up to last space character index per line.(default value is -1 means no space in that line). Then it will put line break after last space if the number of characters on that line is more than 30. How ever this algorithm test other things too to better handle text formatting.
This is done every time a textbox value is changed. StringBuilder is used instead of string to increase performance.
To prevent stack overflow exception as described by #KhaksarWeqar I used a boolean value _isInsideTextChanged with TextChanged event:
private bool _isInsideTextChanged = false;
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (_isInsideTextChanged) return; // return if was inside TextChanged.
_isInsideTextChanged = true; // inside TextChanged
// Do stuff...
_isInsideTextChanged = false; // outside TextChanged
}
There is also a better way explained on wiki. you can create your own even better!. https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap

how to remove space after pressing buttons

i was doing a ITP assignment, when i got an error. The code for the part with the problem is:
private void btnAddWord_Click(object sender, EventArgs e)
{
//if the textbox is empty
if (string.IsNullOrEmpty(tbxAddWord.Text))
{
MessageBox.Show("You have entered no characters in the textbox.");
tbxAddWord.Focus();
}
//if the number of items in the listbox is greater than 29
else if (lbxUnsortedList.Items.Count > 29)
{
MessageBox.Show("You have exceeded the maximum number of words in the list.");
tbxAddWord.Text = "";
}
//error message for entering word that is already in the list
bool contains = false;
for (int i = 0; i < lbxUnsortedList.Items.Count; i++)
{
if (lbxUnsortedList.Items[i].ToString().ToLower() == this.tbxAddWord.Text.ToString().ToLower())
{
contains = true;
}
}
//if there is no match in the list
if (!contains)
{
//add word to the listbox
lbxUnsortedList.Items.Add(tbxAddWord.Text);
//update tbxListBoxCount
tbxListboxCount.Text = lbxUnsortedList.Items.Count.ToString();
//onclick, conduct the bubble sort
bool swapped;
string temp;
do
{
swapped = false;
for (int i = 0; i < lbxUnsortedList.Items.Count - 1; i++)
{
int result = CarNameData[i].ToString().CompareTo(CarNameData[i + 1]);
if (result > 0)
{
temp = CarNameData[i];
CarNameData[i] = CarNameData[i + 1];
CarNameData[i + 1] = temp;
swapped = true;
}
}
} while (swapped == true);
tbxAddWord.Text = "";
}
// if there is a match in the list
else
{
MessageBox.Show("The word that you have added is already on the list");
tbxAddWord.Text = "";
tbxAddWord.Focus();
}
}
When i leave the textbox blank and click the add button, it comes up with the error message, but still adds a blank space. how do i stop this from happening?
You need to return from the method if you don't want to execute more code:
if (string.IsNullOrEmpty(tbxAddWord.Text))
{
MessageBox.Show("You have entered no characters in the textbox.");
tbxAddWord.Focus();
return;
}
//if the number of items in the listbox is greater than 29
else if (lbxUnsortedList.Items.Count > 29)
{
MessageBox.Show("You have exceeded the maximum number of words in the list.");
tbxAddWord.Text = "";
return;
}
First thing is if you are using CarNameData list as Generic collection list List<string> its allows inbuilt sort method like CarNameData.Sort();
Second thing you have to put your code in else part like this
private void btnAddWord_Click(object sender, EventArgs e)
{
//if the textbox is empty
if (string.IsNullOrEmpty(tbxAddWord.Text))
{
MessageBox.Show("You have entered no characters in the textbox.");
tbxAddWord.Focus();
}
else
{
//if the number of items in the listbox is greater than 29
if (lbxUnsortedList.Items.Count > 29)
{
MessageBox.Show("You have exceeded the maximum number of words in the list.");
tbxAddWord.Text = "";
}
//error message for entering word that is already in the list
bool contains = false;
for (int i = 0; i < lbxUnsortedList.Items.Count; i++)
{
if (lbxUnsortedList.Items[i].ToString().ToLower() == this.tbxAddWord.Text.ToString().ToLower())
{
contains = true;
}
}
//if there is no match in the list
if (!contains)
{
//add word to the listbox
lbxUnsortedList.Items.Add(tbxAddWord.Text);
//update tbxListBoxCount
tbxListboxCount.Text = lbxUnsortedList.Items.Count.ToString();
//onclick, conduct the bubble sort
bool swapped;
string temp;
do
{
swapped = false;
for (int i = 0; i < lbxUnsortedList.Items.Count - 1; i++)
{
int result = CarNameData[i].ToString().CompareTo(CarNameData[i + 1]);
if (result > 0)
{
temp = CarNameData[i];
CarNameData[i] = CarNameData[i + 1];
CarNameData[i + 1] = temp;
swapped = true;
}
}
} while (swapped == true);
tbxAddWord.Text = "";
}
// if there is a match in the list
else
{
MessageBox.Show("The word that you have added is already on the list");
tbxAddWord.Text = "";
tbxAddWord.Focus();
}
}
}

Richtextbox lines count

I'm developing a text editor in C#, and I'm trying to make a line count.
private void updateNumberLabel()
{
Point pos = new Point(0, 0);
int firstIndex = Document.GetCharIndexFromPosition(pos);
int firstLine = Document.GetLineFromCharIndex(firstIndex);
pos.X = ClientRectangle.Width;
pos.Y = ClientRectangle.Height;
int lastIndex = Document.GetCharIndexFromPosition(pos);
int lastLine = Document.GetLineFromCharIndex(lastIndex);
int actualLine = Document.GetLineFromCharIndex(actualPos);
pos = Document.GetPositionFromCharIndex(lastIndex);
if (lastLine != actualLine)
{
numberLabel.Text = "";
for (int i = firstLine; i <= lastLine + 1; i++)
{
numberLabel.Text += i + 1 + "\n";
}
}
}
It works fine and adds the number of lines while you write them, but if you delete one, it will only update if you delete or add one more line.
I want make it instantaneous. If you delete one, the count shall be decreased instantaneously.
Maybe this is too easy, but what about that:
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
var lineCount = richTextBox.Lines.Count();
numberLabel.Text = lineCount.ToString();
}
Make sure you assign it to the TextChanged event.
If this is not what you need, please add some more information what you are trying to achieve.
I'm really late, but Lines is an array of string. Just get the length.
richTexBox.Lines.Length.ToString();
I have found one open source and applied it to this problem.
I have confirmed that it works well and have implemented it.
RichTextBox Colums and Row
Simple Code(
The link has a demo source.):
this.rtb.CursorPositionChanged +=
new System.EventHandler(this.rtb_CursorPositionChanged);
this.rtb.SelectionChanged +=
new System.EventHandler(this.rtb_SelectionChanged);
.
.
.
private void rtb_CursorPositionChanged(object sender, System.EventArgs e)
{
int line = rtb.CurrentLine;
int col = rtb.CurrentColumn;
int pos = rtb.CurrentPosition;
statusBar.Text = "Line " + line + ", Col " + col +
", Position " + pos;
}
private void rtb_SelectionChanged(object sender, System.EventArgs e)
{
int start = rtb.SelectionStart;
int end = rtb.SelectionEnd;
int length = rtb.SelectionLength;
statusBar.Text = "Start " + start + ", End " + end +
", Length " + length;
}
namespace Nik.UserControls
{
public class RicherTextBox2 : System.Windows.Forms.RichTextBox
{
public event EventHandler CursorPositionChanged;
protected virtual void OnCursorPositionChanged( EventArgs e )
{
if ( CursorPositionChanged != null )
CursorPositionChanged( this, e );
}
protected override void OnSelectionChanged( EventArgs e )
{
if ( SelectionLength == 0 )
OnCursorPositionChanged( e );
else
base.OnSelectionChanged( e );
}
public int CurrentColumn
{
get { return CursorPosition.Column( this, SelectionStart ); }
}
public int CurrentLine
{
get { return CursorPosition.Line( this, SelectionStart ); }
}
public int CurrentPosition
{
get { return this.SelectionStart; }
}
public int SelectionEnd
{
get { return SelectionStart + SelectionLength; }
}
}
internal class CursorPosition
{
[System.Runtime.InteropServices.DllImport("user32")]
public static extern int GetCaretPos(ref Point lpPoint);
private static int GetCorrection(RichTextBox e, int index)
{
Point pt1 = Point.Empty;
GetCaretPos(ref pt1);
Point pt2 = e.GetPositionFromCharIndex(index);
if ( pt1 != pt2 )
return 1;
else
return 0;
}
public static int Line( RichTextBox e, int index )
{
int correction = GetCorrection( e, index );
return e.GetLineFromCharIndex( index ) - correction + 1;
}
public static int Column( RichTextBox e, int index1 )
{
int correction = GetCorrection( e, index1 );
Point p = e.GetPositionFromCharIndex( index1 - correction );
if ( p.X == 1 )
return 1;
p.X = 0;
int index2 = e.GetCharIndexFromPosition( p );
int col = index1 - index2 + 1;
return col;
}
}
}
Los799
Sorry for answering a "bit" late, I saw this question just now.
But if the problem still stands, here's a simple way to count lines, just use a foreach loop:
int CountOfLines = 1;//1 because min 1 line is always in a text of a control, that has a Text property
foreach (char c in YourText)
{
if (c == '\r' | c == '\n')//these are all equal the ENTER key
{
CountOfLines++;
}
}
You can also use foreach to count characters as well, but with foreach you can choose characters, that you don't want to be counted in the count of characters. For example:
int CountOfCharacters = 0;//0 because by default there are no characters in a textbox or label.
foreach (char c in YourText)
{
if (c != '\t' & c != '\n' & c != '\r')//in this example I want to count only the characters that are not an ENTER or a TAB.
{
CountOfCharacters++;
}
}
Hope this helps you and everybody else, who's reading this, even if it's a bit late answer. :)
Instead of trying to battle with the default rich text box, why don't you try making your own control so you have full control of the text formatting?
After all, if you're developing your own text editor, it would make sense to have text stored and managed in a way that makes sense to you, the developer, instead of trying to fight with a format designed for a slightly different purpose.
Newer solution to this question for WPF applications
DOK1 is a WPF flow document
TX1 is a TextBox control
TX1.Text = DOK1.Blocks.Count.ToString();

Categories

Resources