Vertical scroll Scintilla Textbox during Text Changed event - c#

Setting a Scintilla.Net textbox with a string and scrolling to last line doesn't work.
This Q & A How make autoscroll in Scintilla? has the answer but it wont work at the same time as setting the text.
Bare bones repro:
private void button1_Click(object sender, EventArgs e)
{
string s = RandomString(400);
scintilla1.Text = s + " " + s + " " + s + " " + s + " " + s;
scintilla1.Scrolling.ScrollBy(0, 10000); //<-doesn't work (but does work eg in a Button2_click)
}
private static Random random = new Random((int)DateTime.Now.Ticks);
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
return builder.ToString();
}
Does anyone know how to scroll vertically down to end line after setting the text?

Well you can try to put Refresh() after adding the text;
scintilla1.Text = s + " " + s + " " + s + " " + s + " " + s;
scintilla1.Refresh();
for this case i found out that you will need to Refresh() twice depend on the length of the string you put on the textbox.

For anyone wondering in the end I ditched Scintilla in favor of ICSharpCode.TextEditor. <- This one was a little unstable so I used the Digitalrune version of the ICsharp.TextEditor
I found enhancing the ICSharpCode.TextEditor was trivial compared with Scintilla.
Another huge benefit of ICSharpCode.TextEditor is that allows you to customize/build your own Syntax Highlighting, eg: https://github.com/icsharpcode/SharpDevelop/wiki/Syntax-highlighting

Related

C# multiple increments

I have, code who do for me "x + y = z"
if (command.Contains("+")) // string polecenie = "";'
{
polecenie = "{" + command + ")";
polecenie = polecenie.Replace("+", "}(");
double a = Convert.ToDouble(Between(polecenie, "{", "}"));
double b = Convert.ToDouble(Between(polecenie, "(", ")"));
double wyn = a + b;
richTextBox1.Text += a + " + " + b + " is " + wyn + "\r\n";
}
And when 'command' is "4+5","3 + 4" or something like this code works, but when i try to do "4 + 3 + 23" it don't work. Final string with starting 'command' "4+5+6", polecenie is: "{4}(5}(6)"... The Between Method:
public string Between(string content, string First, string Last)
{
string end = "";
int Plc1 = content.IndexOf(First) + First.Length;
int Plc2 = content.IndexOf(Last);
end = content.Substring(Plc1, Plc2 - Plc1);
return end;
}
How can I do that? (I want it to work with all possible additions ("4+4","34+5+54","43+4+65+54"...)
You could use the DataTable object to not re-invent the wheel.
richTextBox1.Text = string.Format("{0} is {1}\r\n", command,
(new System.Data.DataTable()).Compute(command, string.Empty));
This would support +, -, *, / and % (mod) operators. For more: https://msdn.microsoft.com/en-us/library/system.data.datacolumn.expression.aspx

Make points progress like Visual studio?

Iam a novice programmer who basically just started,im not sure what I should search for my issue,what I wanna do is making those points like Visual studio if someone already saw VS 2012-13 already installing , those points keep progressing and dissapearing ,hope some can help me out.
Have you tried with ascii and a label?
You can manage to wait for the process load and stuff so meanwhile you can show this:
label l1 = new label();
label.Location = new Point(X location, Y location) //Location despends on you
and then just add this in:
public Form1()
{
InitializeComponent();
label l1 = new label();
label.Location = new Point(X location, Y location) //Location despends on you
_load();
}
Create a timmer method:
private async void _load()
{
string[] n = { " ", " ", " ", " ", " ", " ", " ", " ", " ", " " };
while (true)
{
l1.Text = "• • • • •";
await Task.Delay(500);
for(int i=0; i<10; i++)
{
if (i < 4)
{
await Task.Delay(50);
l1.Text = "• • • •" + n[i] + "•";
}
else if(i >4 && i< 7)
{
await Task.Delay(100);
l1.Text = "• • • •" + n[i] + "•";
}
else
{
await Task.Delay(180);
l1.Text = "• • • •" + n[i] + "•";
}
}
}
}
You just have to use the head to guess how to make it look like the VS's one D:
Strings are funny :3
Don't do that. Microsoft is violating their own UI guidelines. (See #11 here].
Instead, indicate progress using a standard ProgressBar control. That's what it is for, and all your users already recognize its meaning.
The animation you indicate is most similar to the Marquee style of the standard progress bar.

From DataGridView to multiline commaSeparated string

I have a DataGridView with four Columns and need to crate a multiline string from its content, separated by comma.
This code works, but probably - there is a more elegant way:
string multiLine = "";
string singleLine;
foreach (DataGridViewRow r in dgvSm.Rows)
{
if (!r.IsNewRow)
{
singleLine = r.Cells[0].Value.ToString() + ","
+ r.Cells[1].Value.ToString() + ","
+ r.Cells[2].Value.ToString() + ","
+ r.Cells[3].Value.ToString() + Environment.NewLine;
multiLine = multiLine + singleLine;
}
}
I don't know about elegant, but:
use StringBuilder for string manipulation, type string is immutable!
if you need to do something in between, separate first or last cycle running (e.g. comma separation)
So, basically something like this:
StringBuilder multiLine = new StringBuilder();
foreach (DataGridViewRow r in dgvSm.Rows)
{
if (!r.IsNewRow)
{
if (r.Cells.Count > 0)
{
multiLine.Append(r.Cells[0].Value.ToString()); //first separated
for (int i = 1; i < r.Cells.Count; ++i)
{
singleLine.Append(','); //between values
singleLine.Append(r.Cells[i].Value.ToString());
}
multiLine.AppendLine();
}
}
}
To illustrate speed difference between StringBuilder concatenation (just dynamic array of characters) and string (new object and copy everything each time you use operator + concatenation), have a look at mini-program:
public static void Main()
{
var sw = new Stopwatch();
sw.Start();
StringBuilder s = new StringBuilder();
//string s = "";
int i;
for (i = 0; sw.ElapsedMilliseconds < 1000; ++i)
//s += i.ToString();
s.Append(i.ToString());
sw.Stop();
Console.WriteLine("using version with type " + s.GetType().Name + " I did " +
i + " times of string concatenation.");
}
For my computer it is:
using version with type String I did 17682 times of string concatenation.
using version with type StringBuilder I did 366367 times of string concatenation.
Try this :
string multiLine = "";
string singleLine;
foreach (DataGridViewRow r in dgvSm.Rows)
{
if (!r.IsNewRow)
{
singleLine = r.Cells[0].Value.ToString() + ","
+ r.Cells[1].Value.ToString() + ","
+ r.Cells[2].Value.ToString() + ","
+ r.Cells[3].Value.ToString() + "\r\n";
multiLine = multiLine + singleLine;
}
}

How to make a label scroll a word back and forth?

I came up with the idea of making a label scroll a word to one side and then change the word and scroll back to the other like so
"ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping"
" pong"
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
"pong "
I want it to do ^^ only in a constant loop but I don't know how I would even get started doing that I would REALLY appreciate it if someone could help me with this. The max length of the text has to be 15 characters.
I don't care if it is smooth scrolling.
I want it to be a Winforms application and use .Net framework 4.0.
Here's what I would do, it seemed to work just fine when I tested it out, I created a windows form with a timer and label on it. Make sure to call timer.Start() when you open the form and it will start bouncing around the screen. If you change iUBound to a larger value it will move more spaces across the screen.
string _sPing = "ping";
string _sPong = "pong";
bool bGoingUp = true;
int iUBound = 15;
int iCnt = 1;
public Form1()
{
InitializeComponent();
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (bGoingUp)
{
label1.Text = " " + label1.Text;
iCnt++;
}
else
{
label1.Text = label1.Text.Substring(1,label1.Text.Length - 1);
iCnt--;
}
if (iCnt == iUBound)
{
bGoingUp = false;
label1.Text = label1.Text.Replace(_sPing, _sPong);
}
else if (iCnt == 1)
{
bGoingUp = true;
label1.Text = label1.Text.Replace(_sPong, _sPing);
}
}
I'd keep the label contents the same and just move the label, feels like it should be less CPU load and the scrolling will be smoother.
Make a for-loop that runs from 0 to 11 (15 - length of "ping"). With new String(' ', i) you can create a string that is i spaces long. Then set the Text of your label to this space string concatenated with the word "ping".
Now you can make another loop, running from 11 down to 0 doing the same but with the word "pong".
If you enclose both loops in an endless loop (while (true) { ... }) this will run indefinitely.
You also might want to add a pause each time after you set the label text with Thread.Sleep(200). Where you specify the time is in milliseconds.
EDIT (since it is not homework):
Go to the events tab in the properties window and add a Shown event handler
private void frmMarquee_Shown(object sender, EventArgs e)
{
while (true) {
for (int i = 0; i <= 11; i++) {
label1.Text = new String(' ', i) + "ping";
System.Threading.Thread.Sleep(100);
Application.DoEvents();
}
for (int i = 11; i >= 0; i--) {
label1.Text = new String(' ', i) + "pong";
System.Threading.Thread.Sleep(100);
Application.DoEvents();
}
}
}
Note, this solution is not perfect, as the form will not close properly. You will have to abort the program. A solution using a timer will work smoother and the form will behave as expected when closing, however this is a straightforward and simple solution.
I found this example. Pretty close to what you want. The two key elements are (1)using StringBuilder functions to append characters and (2) an asynchronous delegate to put the animation in a different thread.
The idea of the StringBuilder is great because it should be more efficient that dealing with String. And I like Asynchronous delegate because it sounds way more impressive than Timer

How to optimize this code?

Surely there has to be many ways to optimize the following code, where I basically have to make sure that a lot of textboxes aren't empty and then read their values:
if (foo1.Text.Length != 0 & bar1.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo1.Text + " / " + bar1.Text;
}
if (foo2.Text.Length != 0 & bar2.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo2.Text + " / " + bar2.Text;
}
if (foo3.Text.Length != 0 & bar3.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo3.Text + " / " + bar3.Text;
}
if (foo4.Text.Length != 0 & bar4.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo4.Text + " / " + bar4.Text;
}
if (foo5.Text.Length != 0 & bar5.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo5.Text + " / " + bar5.Text;
}
if (foo6.Text.Length != 0 & bar6.Text.Length != 0)
output.Text += myStrings[i] + " / " + foo6.Text + " / " + bar6.Text;
if (foo7.Text.Length != 0 & bar7.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo7.Text + " / " + bar7.Text;
}
if (foo8.Text.Length != 0 & bar8.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo8.Text + " / " + bar8.Text;
}
if (foo9.Text.Length != 0 & bar9.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo9.Text + " / " + bar9.Text;
}
if (foo10.Text.Length != 0 & bar10.Text.Length != 0)
{
output.Text += myStrings[i] + " / " + foo10.Text + " / " + bar10.Text;
}
I would put the repeated elements in arrays and then loop over them.
TextBox[] foos = new TextBox[] { foo1, foo2, foo3, /* etc */ };
TextBox[] bars = new TextBox[] { bar1, bar2, bar3, /* etc */ };
for (int i = 0; i <= 10; i++)
if (foos[i].Text.Length != 0 && bars[i].Text.Length != 0)
output.Text += myStrings[i] + "/" + foos[i].Text + bars[i].Text;
Of course, if the elements are really named sequentially you can fill the arrays by looking up the controls from the form's Controls collection, with the name "foo" + number.ToString().
I would just loop over the Controls collection on which these TextBoxes reside, then filter on TextBox only and do you checks and concat.
I also strongly advice to use a StringBuilder instead of +=.
There are a lot of ways to refactor this. The method you choose will depend on your particular scenario and needs.
Make a function that takes a foo and a bar as a parameter and returns the string, then aggregate that string in a string builder
Put the foos and bars into collections and loop over those collections. In this scenario, arrays would be useful and provide a way to mutually index the arrays.
Take item 2 one step further and create a new class FooBar that holds a foo and a bar together. This way you can create a collection of FooBars and you don't have an implicit association between them anymore, now it's explicit and codified.
Take item 3 one step further and recognize that you're aggregating a string. If you're in a recent version of c#, take advantage of your Map/Reduce in LINQ (.Select().Aggregate()) to transform your FooBars into their corresponding strings, and then to aggregate the strings into output.
This is all just the stuff off the top of my head. If you work at it more, I'm sure you can do even better. :)
(If this is homework, please add a homework tag.)
EDIT:
I can't help but wonder about the design of the UI in general based upon your comment in another post stating that it takes "many seconds" to concatenate the strings together. 10 strings is a pretty trivial amount of time on its own, but this suggests that your outer loop (that's generating i) is fairly long running.
If you're in a position where you have the freedom to make such decisions, are you certain that your UI is actually good for the task at hand? A large collection of pairs of text boxes is a difficult user interface in general. Perhaps a ListView would be more appropriate. It would implicitly contain a collection, so you wouldn't have to deal with this "ten text boxes" silliness and will be an easier UI for your users to follow in general.
Write a function which accepts foo & bar types. Pass all foo1 & bar1 to foo10 and bar10 to the function to get the values. You can also create array of foo and bar and you can loop and call the method to get the string.
foreach (Control ctrl in Page.Controls) {
if (ctrl is TextBox) {
if (ctrl.Text.Length != 0) {
output.Text += myStrings[i] + "/" + ctrl.Text;
}
}
}
Untested , but should work. With this your textboxes could be named anything.
Could you make foo1-foo10 into an array, foo[10], and the same for bar? That would allow you to express this as a simple loop.
Would it be feasible to make a WebControl that has textboxes called foo and bar, and that has a function like:
if (foo.Text.Length != 0 & bar.Text.Length != 0)
return myStrings[i] + " / " + foo.Text + " / " + bar.Text;
else
return string.Empty;
Put ten of those on your page, then use:
output.Text = myControl1.FooBar + myControl2.FooBar + myControl3.FooBar + ...
(Still a bit messy, but not quite so repetitive.)

Categories