Filling a textbox with limited size - c#

I have a textbox control from DevExpress and we cant allow more characters beyond its capacity. The problem is that the input string is xml formatted and can have multiple fonts. If the font size increases, the maximum number of characters decrease.
My first thought is counting by line, because lines are measurable despite font size. But the column I could not see a way.
How could I fill this textbox taking in consideration the string font e xml tags ?

You can use Exception Handling to figure it out for you:
bool flag = false;
int count = line.Length;
do
{
try
{
txt.Text = line.SubString(0, count);
flag = true;
}
catch(TheException)
{
count--;
}
}
while(!flag);
This works if you are getting an exception for putting in too long a line.

Related

fastest way of applying color to specified line of richtextbox?

I'm making text filter.
The source text file is loaded in richtextbox.
I coded to change color of the whole sentence which contains the key-string defined in filter.
In below code, it took very long time to complete due to this code "this.richTextBox1.Lines[lineCount].Length". It almost takes about tens seconds.
The total number of lines of richtextbox is about 15000.
When I fix any constant number instead of "this.richTextBox1.Lines[lineCount].Length", it finish within a few second. Is there any smartter way to apply color to certain line of richtextbox?
foreach (string line in this.richTextBox1.Lines)
{
if (filterKeyString != "")
{
if (line.Contains(filterKeyString)
{
this.lbFilterOut1.Items.Add(line);
lineNum1.Add(lineCount);
offset = this.richTextBox1.GetFirstCharIndexFromLine(lineCount);
this.richTextBox1.Select(offset, this.richTextBox1.Lines[lineCount].Length);
this.richTextBox1.SelectionColor = Color.FromName(filterSet[0].color);
}
}
lineCount++;
}

Programmatically adjust row width on DataGridView to prevent ellipsis

I have a DataGridView that loads lots of data, and I'd like it to do something that is in practice equivalent to setting a particular column's AutoSizeMode to AllCells, but without the performance penalty.
I think I should be able to see which cells are visible by capturing the CellPainting event, which will fire for currently visible cells. Also, since I'm using "Consolas" font which is monospaced, and I know all values will be single lined, measuring any sample string should be enough to calculate the proper width of the cell.
This is what I'm currently doing:
private int MaxLength;
private void DataGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
// DatabaseLog.Columns.Text is the index of the column I want to adjust the width for
if (e.ColumnIndex == DatabaseLog.Columns.Text && e.FormattedValue is string text && text.Length > MaxLength)
{
text += "-"; // Just to be safe
MaxLength = text.Length;
// And to be extra safe measure it both ways and use the largest one:
var width1 = (int)Math.Ceiling(e.Graphics.MeasureString(text, e.CellStyle.Font).Width); // To be even safer use Ceiling
var width2 = TextRenderer.MeasureText(text, e.CellStyle.Font).Width;
// Use a task in case DataGridView doesn't want to repaint since this is CellPainting
Task.Run(() => BeginInvoke(new Action(() =>
dataGridView.Columns[DatabaseLog.Columns.Text].Width = Math.Max(width1, width2) + e.CellStyle.Padding.Horizontal // Also, add padding
)));
}
}
Which, on lines longer than about 100 characters will still show an ellipsis. If I change the line text += "-"; to text += "-----"; it works, but since that's just an arbitrary number of characters, there's no way to tell if it'll work all the time. So I wonder if there's anything I'm missing here that I should add to my width.

How can I replace a unicode string in a binary file?

I've been trying to get my program to replace unicode in a binary file.
The user would input what to find, and the program would find and replace it with a specific string if it can find it.
I've searched around, but there's nothing I can find to my specifics, what I would like would be something like:
string text = File.ReadAllText(path, Encoding.Unicode);
text = text.Replace(userInput, specificString);
File.WriteAllText(path, text);
but anything that works in a similar manner should suffice.
Using that results in a file that is larger and unusable, though.
I use:
int var = File.ReadAllText(path, Encoding.Unicode).Contains(userInput) ? 1 : 0;
if (var == 1)
{
//Missing Part
}
for checking if the file contains the user inputted string, if it matters.
This can work only in very limited situations. Unfortunately, you haven't offered enough details as to the nature of the binary file for anyone to know if this will work in your situation or not. There are a practically endless variety of binary file formats out there, at least some of which would be rendered invalid if you modify a single byte, many more of which could be rendered invalid if the file length changes (i.e. data after your insertion point is no longer where it is expected to be).
Of course, many binary files are also either encrypted, compressed, or both. In such cases, even if you do by some miracle find the text you're looking for, it probably doesn't actually represent that text, and modifying it will render the file unusable.
All that said, for the sake of argument let's assume your scenario doesn't have any of these problems and it's perfectly okay to just completely replace some text found in the middle of the file with some entirely different text.
Note that we also need to make an assumption about the text encoding. Text can be represented in a wide variety of ways, and you will need to use the correct encoding not just to find the text, but also to ensure the replacement text will be valid. For the sake of argument, let's say your text is encoded as UTF8.
Now we have everything we need:
void ReplaceTextInFile(string fileName, string oldText, string newText)
{
byte[] fileBytes = File.ReadAllBytes(fileName),
oldBytes = Encoding.UTF8.GetBytes(oldText),
newBytes = Encoding.UTF8.GetBytes(newText);
int index = IndexOfBytes(fileBytes, oldBytes);
if (index < 0)
{
// Text was not found
return;
}
byte[] newFileBytes =
new byte[fileBytes.Length + newBytes.Length - oldBytes.Length];
Buffer.BlockCopy(fileBytes, 0, newFileBytes, 0, index);
Buffer.BlockCopy(newBytes, 0, newFileBytes, index, newBytes.Length);
Buffer.BlockCopy(fileBytes, index + oldBytes.Length,
newFileBytes, index + newBytes.Length,
fileBytes.Length - index - oldBytes.Length);
File.WriteAllBytes(filename, newFileBytes);
}
int IndexOfBytes(byte[] searchBuffer, byte[] bytesToFind)
{
for (int i = 0; i < searchBuffer.Length - bytesToFind.Length; i++)
{
bool success = true;
for (int j = 0; j < bytesToFind.Length; j++)
{
if (searchBuffer[i + j] != bytesToFind[j])
{
success = false;
break;
}
}
if (success)
{
return i;
}
}
return -1;
}
Notes:
The above is destructive. You may want to run it only on a copy of the file, or prefer to modify the code so that it takes an addition parameter specifying the new file to which the modification should be written.
This implementation does everything in-memory. This is much more convenient, but if you are dealing with large files, and especially if you are on a 32-bit platform, you may find you need to process the file in smaller chunks.

RichTextBox - sorting lines randomly

I want to write an application which sorts randomly line of text which I copy from a source and paste into RichTextBox area.
However, there is one condition - text is formatted (some words are in bold, underline etc.). So any suggestions? How should it look like?
I think I should use RichTextBox.Rtf or something but I am really a beginner and I appreciate every hint or example code.
Thanks
It is a bit tricky. You can retrieve the formatted RTF text lines like this
string[] rtfLines = new string[richTextBox1.Lines.Length];
for (int i = 0; i < rtfLines.Length; i++) {
int start = richTextBox1.GetFirstCharIndexFromLine(i);
int length = richTextBox1.Lines[i].Length;
richTextBox1.Select(start, length);
rtfLines[i] = richTextBox1.SelectedRtf;
}
Now you can shuffle the lines like this
var random = new Random();
rtfLines = rtfLines.OrderBy(s => random.NextDouble()).ToArray();
Clear the RichtTextBox
richTextBox1.Text = "";
Inserting the lines is best done in reverse order because it is easier to select the beginning of the text
// Insert the line which will be the last line.
richTextBox1.Select(0, 0);
richTextBox1.SelectedRtf = rtfLines[0];
// Prepend the other lines and add a line break.
for (int i = 1; i < rtfLines.Length; i++) {
richTextBox1.Select(0, 0);
// Replace the ending "}\r\n" with "\\par }\r\n". "\\par" is a line break.
richTextBox1.SelectedRtf =
rtfLines[i].Substring(0, rtfLines[i].Length - 3) + "\\par }\r\n";
}
The task seems not complicated(if I understand it correctly).
Get your clipboard into string then parse into array- use Split().
Then determine how many randon events you need and iterate through every word ; generate random number for each iteration(which should match the amount of events), intersect that number with one of the events and apply that case to that particular word. Maybe not the most efficient way to do it, but that's what comes to my mind

Faster Way to Color All Occurences in a RichTextBox in C#

I have a RichTextBox, and there are about more than 1000 occurrences of a specified search string.
I use the following function to color all the occurrences:
public void ColorAll(string s)
{
rtbxContent.BeginUpdate();
int start = 0, current = 0;
RichTextBoxFinds options = RichTextBoxFinds.MatchCase;
start = rtbxContent.Find(s, start, options);
while (start >= 0)
{
rtbxContent.SelectionStart = start;
rtbxContent.SelectionLength = s.Length;
rtbxContent.SelectionColor = Color.Red;
rtbxContent.SelectionBackColor = Color.Yellow;
current = start + s.Length;
if (current < rtbxContent.TextLength)
start = rtbxContent.Find(s, current, options);
else
break;
}
rtbxContent.EndUpdate();
}
But I found it's very slow.
However, if I color all the occurrences of another word, which has less number of occurrences in the same text, I found it's very fast.
So I guess the slowness is from (these two line might get UI refresh involved):
rtbxContent.SelectionColor = Color.Red;
rtbxContent.SelectionBackColor = Color.Yellow;
Is there a faster way of doing the same job, such as, I do the coloring in the memory, and then I display the result at one-go?
Do I make myself clear?
Thanks.
The amount of time it takes is directly proportional to the number of occurances.
It is probably the Find that is using the most time. You could replace this line:
start = rtbxContent.Find(s, start + s.Length, options);
with this:
start = rtbxContent.Find(s, current, options);
Since you have computed current to equal start + s.Length
You could also store s.Length is a variable so you do not need to count all the characters in a string each time. The same goes for rtbxContent.TextLength.
There is a faster way.
Use regex to find the matches then highlight in the richtextbox
if (this.tBoxFind.Text.Length > 0)
{
try
{
this.richTBox.SuspendLayout();
this.Cursor = Cursors.WaitCursor;
string s = this.richTBox.Text;
System.Text.RegularExpressions.MatchCollection mColl = System.Text.RegularExpressions.Regex.Matches(s, this.tBoxFind.Text);
foreach (System.Text.RegularExpressions.Match g in mColl)
{
this.richTBox.SelectionColor = Color.White;
this.richTBox.SelectionBackColor = Color.Blue;
this.richTBox.Select(g.Index, g.Length);
}
}
finally
{
this.richTBox.ResumeLayout();
this.Cursor = Cursors.Default;
}
}
The string search is linear. If you find Find method to be slow, maybe you can use third party tool to do the searching for you. All you need is index of the pattern in a string.
Maybe this will help you. You should time the difference and use the faster one.
You're on the right track that Winforms' slow RichTextBox implementation is to blame. You also did well to use the BeginUpdate and EndUpdate methods (I'm guessing you took those from here?). But alas, that isn't enough.
A couple of solutions:
1: Try writing the RTF directly to the textbox. This is a fairly messy, complicated format, but luckily, I have created an answer here which will do the trick.
2: This highly rated external project also looks well worth a look: http://www.codeproject.com/Articles/161871/Fast-Colored-TextBox-for-syntax-highlighting

Categories

Resources