Is there any way i can display a String character by character? like in old RPGs
I've tried this:
string text1 ="this is a text";
for (int i = 0; i < text1.Length; i++)
{
textBox1.Text = "" + text1[i];
}
but it only replaces the last character on the text box.
Try This:
public partial class Form1 : Form
{
int count = 0;
string text1 = "this is a scrolling text";
System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
textBox1.ReadOnly = true;
SetTimer(500);
}
private void SetTimer(int milliseconds)
{
timer1.Tick+=new EventHandler(timer1_Tick);
timer1.Interval = milliseconds;
timer1.Start();
}
private void timer1_Tick(Object o, EventArgs e)
{
if (count < text1.Length)
{
textBox1.Text += text1[count];
count++;
}
else
{
timer1.Stop();
button1.Enabled = true;
textBox1.ReadOnly = false;
}
}
}
Output:
The following code should do it:
public Form1()
{
InitializeComponent();
TypeText("this is a text");
}
private void TypeText(string text)
{
textBox1.Clear(); // Make sure the textbox is empty
Thread thread = new Thread(delegate() // Create a new thread which fills the textbox periodically
{
button1.BeginInvoke((MethodInvoker)delegate { button1.Enabled = false; }); // Disables the button
for (int i = 0; i < text.Length; i++)
{
int temp = i; // Cache variable because without this, an 'ArgumentOutOfRange' Exception will be thrown
textBox1.BeginInvoke((MethodInvoker)delegate // Invoke to main thread
{
textBox1.Text += text[temp]; // Fill with next char
});
if (text[temp] != ' ') // This makes sure the user doesn't have to wait the double of the time when there is an empty space for the new character
Thread.Sleep(500); // This will stop the seperate thread for 500ms. Won't block the main thread
}
button1.BeginInvoke((MethodInvoker)delegate { button1.Enabled = true; }); // Reenables the button
});
thread.Start(); // Start the new thread and continue the main thread
}
I'm not sure exactly how that helps you. You might want to add why you are doing this. The issue you are having with your code is that your are not appending to the string. Try this line instead:
textBox1.Text += text1[i];
You need to clear textBox1.Text before you start (set it to "").
A better approach might be to print out the hex values so that non printing characters are easily seen. You can do something like this:
string text1 ="this is a text";
var sb = new StringBuilder();
for (int i = 0; i < text1.Length; i++) {
sb.AppendFormat("{0:X} ", text1[i]);
}
textBox1.Text = sb.ToString();
Reading Jeroen Vannevel makes me thing that you are trying to create a "typewriter" affect. In that case try something like:
string text1 ="this is a text";
textBox1.Text = "";
for (int i = 0; i < text1.Length; i++) {
textBox1.Text += text1[i];
Thread.Sleep(250); // 1/4 sec delay
}
This code was written modeled on the code given. There is an implied expectation that this is run from the main UI thread. This means that when you are sitting in a loop with a Sleep delay your UI will be unresponsive (since you are tying up the main thread). You can overcome this by using the Invoke method on the Dispatcher object (of your App) and running the code on a different thread. You should only Invoke the parts that are owned by the main UI (textBox1) in this case.
textBox1.Text = textBox1.Text + text1[i]
To me it seems that you want to break a string into its characters, there are several ways to do that:
1 - String.GetChar() Method:
http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.strings.getchar%28v=vs.110%29.aspx
2 - String.Chars property:
http://msdn.microsoft.com/en-us/library/system.string.chars%28v=vs.110%29.aspx
TextBox1.Text += MyString.Chars[i];
Then if you want to show them one by one with a delay or something like that, you can use timers as others have suggested.
Related
I want to call RichTextBox.Find() from another thread. How can I do that?
The RichTextBox is located in a UserControl which I'm using in my form.
I want to update it from another thread. I was able to change its properties using Invoke. But can't figure out how to call _ucResultRich.rchResult.Find(word, startIndex, RichTextBoxFinds.None); from my thread.
Thread thread=new Thread(thrHighlight);
thread.Start(e.RowIndex);
private void ThrHighlight(object obj)
{
string[] words = ucSearchControls.rdbExact.Checked
? new string[] { ucSearchControls.txtSearch.Text.Trim() }
: ucSearchControls.txtSearch.Text.Split(' ');
foreach (string word in words)
{
int startIndex = 0;
while (startIndex < _ucResultRich.rchResult.TextLength)
{
int wordStartIndex = _ucResultRich.rchResult.Find(word, startIndex, RichTextBoxFinds.None);
if (wordStartIndex != -1)
{
_ucResultRich.rchResult.SelectionStart = wordStartIndex;
_ucResultRich.rchResult.SelectionLength = word.Length;
_ucResultRich.rchResult.SelectionBackColor = Color.Yellow;
}
else
break;
startIndex += wordStartIndex + word.Length;
}
}
}
How can I do that?
P.S: This is the follow-up to my first question and to the #varocarbas comments there
This answer is exclusively focused on showing how to use properly (i.e., by maximising its in-built functionalities) BackgroundWorker (it is the continuation of some of the comments I wrote in a previous post of the OP) to deliver the intended functionalities.
To use the code below these lines, start a new Winforms project and add the following controls to the main form: Button (button1 with the click event button1), RichTextBox (richTextBox1) and a BackgroundWorker (backgroundWorker1 with the DoWork event backgroundWorker1_DoWork and the ProgressChanged event backgroundWorker1_ProgressChanged); also note that Form1_Load is the Load event of the main form.
To use the application, just input any text in the richTextBox1 by including some of the hardcoded words (i.e., "word1", "word2", "word3", "word4", "word5"), click on button1 and confirm that they are highlighted as expected.
volatile int curWordStartIndex; //I use this global variable to communication between the progressChanged event and findBit, called from the DoWork event
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.WorkerReportsProgress = true;
}
private void button1_Click(object sender, EventArgs e)
{
//As far as richTextBox1.TextLength provokes a cross-thread error, I pass it as an argument
backgroundWorker1.RunWorkerAsync(richTextBox1.TextLength);
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
findBit((int)e.Argument);
}
private void findBit(int textLength)
{
string[] words = new string[] { "word1", "word2", "word3", "word4", "word5" };
foreach (string word in words)
{
int startIndex = 0;
while (startIndex < textLength)
{
//Rather than performing the actions affecting the GUI thread here, I pass all the variables I need to
//the ProgressChanged event through ReportProgress and perform the modifications there.
backgroundWorker1.ReportProgress(0, new object[] { word, startIndex, Color.Yellow });
if (curWordStartIndex == -1) break;
startIndex += curWordStartIndex + word.Length;
}
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
object[] curVars = (object[])e.UserState;
richTextBox1.SuspendLayout();
string word = (string)curVars[0];
int startIndex = (int)curVars[1];
Color curColor = (Color)curVars[2];
curWordStartIndex = richTextBox1.Find(word, startIndex, RichTextBoxFinds.None);
if (curWordStartIndex != -1)
{
richTextBox1.SelectionStart = curWordStartIndex;
richTextBox1.SelectionLength = word.Length;
richTextBox1.SelectionBackColor = curColor;
}
richTextBox1.ResumeLayout();
}
You need to decouple your code a bit from UI controls and do your business logic on external thread and update UI control on Dispatcher.BeginInvoke or Invoke.
For example ,you can save the text that your Textbox has in a separate property and do Find on other thread ,once you are done post the UI highlight part on UI thread.
well i am new to C#, and implementing a code, in which i have two buttons, with one acting as starting of data acquisition and storing it in a csv file and other button to stop it.
well codes for all these are as follows:
//button for start DAQ
private void stdaq_Click(object sender, EventArgs e)
{
stopped = false;
process();
}
//button for stoping DAQ
private void spdaq_Click(object sender, EventArgs e)
{
stopped = true;
}
// process function
private process()
{
int iAvail = 0;
int iRead = 0;
string filename = #textBox3.Text;// taking csv file name from user
// jit:
//a function calculating the total number of values and storing it in iAvail
int[] iRawData = new Int32[iAvail];
double[] dScaledData = new Double[iAvail];
//a function transferring the data from buffer and storing it in dscaledData array
List<double> data = new List<double>();
for (int i = 0; i < iAvail; i++)
{
data.Add(dScaledData[i]);
}
Task myFirstTask = Task.Factory.StartNew(()
=>
{
while (stopped == false)
{
Write(data.ToArray(), filename);
// goto jit;
}
});
}
// csv creater and data writer
public static void Write(double[] data, string outputPath)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.GetLength(0); i++)
{
if (stopped) break;
sb.AppendLine(string.Join(",", data[i]));
}
if (File.Exists(outputPath))
{
File.AppendAllText(outputPath, sb.ToString());
}
else
{
File.WriteAllText(outputPath, sb.ToString());
}
}
this is what i am implementing, and the problem with this code is that when the data is first transferred and written to the file, then again the same data is written again and again irrespective of new data and i tried implementing that Goto statement(can be seen in comments) but it is giving error - " Control cannot leave the body of an anonymous method or lambda expression ", and if i don't use the While loop the data is not written at all.
So i want to call my process function and to transfer data to csv starting on press of a start button, take fresh data everytime and write it to csv or can say call the process method again from it's start point and to stop it on click of the stop button, but i am unable to do it irrespective of various tries with different loops and some threading functions also.
please help with this.
Assuming you only need to Write once, you should remove this or change it from while to if:
while (stopped == false)
The loop will cause Write to be called infinitely until stopped becomes true.
Also, you might want to change Write to return rather than break if stopped is true, so that you don't write anything if you are supposed to be stopping:
if (stopped) break;
to
if (stopped) return;
If you want to generate data again and really do want to loop forever, just move that code into the loop:
Task myFirstTask = Task.Factory.StartNew(()
=>
{
while (stopped == false)
{
List<double> data = new List<double>();
// TODO: Generate data here - move all relevant code here
Write(data.ToArray(), filename);
}
});
I think this is a job for the BackgroundWorker.
This code will start you up:
public partial class Form1 : Form
{
int loopCounter = 0; // variable just used for illustration
private static BackgroundWorker bw = new BackgroundWorker(); // The worker object
// This function does your task
public void doSomeStuff(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 1000; i++)
{
loopCounter = i; // Pass the loop count to this variable just to report later how far the loop was when the worker got cancelled.
Thread.Sleep(100); // Slow down the loop
// During your loop check if the user wants to cancel
if (bw.CancellationPending)
{
e.Cancel = true;
return; // quit loop
}
}
}
// This button starts your task when pressed
private void button1_Click(object sender, EventArgs e)
{
bw.WorkerSupportsCancellation = true; // Set the worker to support cancellation
bw.DoWork += doSomeStuff; // initialize the event
if (!bw.IsBusy) // Only proceed to start the worker if it is not already running.
{
bw.RunWorkerAsync(); // Start the worker
}
}
// This button stops your task when pressed
private void button2_Click(object sender, EventArgs e)
{
// Request cancellation
bw.CancelAsync();
textBox1.Text = "The bw was cancelled when 'loopCounter' was at: " + loopCounter.ToString();
}
}
I'm writing a program, that should replace or remove some entries from a logfile.txt.
The code is working fine ( at least for small LogFiles). If i use a big file (like 27 MB) its getting very slow and the UI freeze. I cant click anything.
On Button click i execute this method:
private string delete_Lines(string[] lines, string searchString)
{
for (int i = 0; i < lines.Length; i++)
{
if (lines[i].Contains(searchString))
{
rtbLog.Text += "Deleting(row " + (i + 1) + "):\n" + lines[i] + "\n";
progressBar1.Value += 1;
if (cbDB == true)
{
while (is_next_line_block(lines, i) == true)
{
i++;
rtbLog.Text += lines[i] + "\n";
progressBar1.Value += 1;
}
}
}
else
{
res += lines[i]+"\n";
progressBar1.Value += 1;
}
}
tssLbl.Text = "Done!";
rtbLog.Text += "...Deleting finished\n";
return res;
}
Lines is the array of the logfile i am trying to clean up. every entry is a single row . tssLbl is a notification label and rtbLog is a richTextBox, where i'am tracking which row i am deleting.
is_next_line_block is just another method, which is checking of the next lines are part of the block i want to delete. The params of this method are the whole lines array and the line position.
private bool is_next_line_block(string[] lines, int curIndex)
{
if (curIndex < lines.Length-1)
{
if (lines[curIndex + 1].StartsWith(" "))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
Have anybody any idea, what is causing that freezes and is slowing down the program? I know, that i could speed my code up by parallelizing it, but i cant imagine, that it takes so long to check up a 27 MB txt file without parallelism.
You have several issues here:
You are reading the whole file in buffer (array of string), I am guessing you are calling File.ReadAllLines(). Reading big files in buffer will slow you down, as well as in extreme case run you out of memory.
You are using += operation for your rich textbox Text property. That is time consuming operation as UI has to render the whole rich text box every time you update the text property that way. Better option is to use string builder to load these text, and update rich text box periodically.
To fix this you need to read the file as stream. Progress can be monitored based on bytes read instead of line position. You can run the read operation async and monitor progression on a timer, as shown in example below.
private void RunFileOperation(string inputFile, string search)
{
Timer t = new Timer();
int progress = 0;
StringBuilder sb = new StringBuilder();
// Filesize serves as max value to check progress
progressBar1.Maximum = (int)(new FileInfo(inputFile).Length);
t.Tick += (s, e) =>
{
rtbLog.Text = sb.ToString();
progressBar1.Value = progress;
if (progress == progressBar1.Maximum)
{
t.Enabled = false;
tssLbl.Text = "done";
}
};
//update every 0.5 second
t.Interval = 500;
t.Enabled = true;
// Start async file read operation
System.Threading.Tasks.Task.Factory.StartNew(() => delete_Lines(inputFile, search, ref progress, ref sb));
}
private void delete_Lines(string fileName, string searchString, ref int progress, ref StringBuilder sb)
{
using (var file = File.OpenText(fileName))
{
int i = 0;
while (!file.EndOfStream)
{
var line = file.ReadLine();
progress = (int)file.BaseStream.Position;
if (line.Contains(searchString))
{
sb.AppendFormat("Deleting(row {0}):\n{1}", (i + 1), line);
// Change this algorithm for nextline check
// Do this when it is next line, i.e. in this line.
// "If" check above can check if (line.startswith(" "))...
// instead of having to do it nextline next here.
/*if (cbDB == true)
{
while (is_next_line_block(lines, i) == true)
{
i++;
rtbLog.Text += lines[i] + "\n";
progressBar1.Value += 1;
}
}*/
}
}
}
sb.AppendLine("...Deleting finished\n");
}
As a follow up to your question on Task.Factory.Start() usage, it's done this way (generally):
// you might need to wrap this in a Dispatcher.BeginInvoke (see below)
// if you are not calling from the main UI thread
CallSomeMethodToSetVisualCuesIfYouHaveOne();
Task.Factory.StartNew(() =>
{
// code in this block will run in a background thread...
}
.ContinueWith(task =>
{
// if you called the task from the UI thread, you're probably
// ok if you decide not to wrap the optional method call below
// in a dispatcher begininvoke...
Application.Current.Dispatcher.BeginInvoke(new Action(()=>
{
CallSomeMethodToUnsetYourVisualCuesIfYouHaveAnyLOL();
}));
}
Hope this helps!
Thanks to everybody for the help, especially loopedcode, That's the working version (Took loopedcode's code and made some edit):
private void RunFileOperation(string inputFile, string search)
{
Timer t = new Timer();
StringBuilder sb = new StringBuilder();
{
rtbLog.Text = "Start Deleting...\n";
}
// Filesize serves as max value to check progress
progressBar1.Maximum = (int)(new FileInfo(inputFile).Length);
t.Tick += (s, e) =>
{
rtbLog.Text += sb.ToString();
progressBar1.Value = progress;
if (progress == progressBar1.Maximum)
{
t.Enabled = false;
tssLbl.Text = "done";
}
};
//update every 0.5 second
t.Interval = 500;
t.Enabled = true;
// Start async file read operation
if (rbtnDelete.Checked)
{
if (cbDelete.Checked)
{
System.Threading.Tasks.Task.Factory.StartNew(() => delete_Lines(inputFile, search, ref progress, ref sb, ref res1));
}
}
else
{
//..do something
}
private void delete_Lines(string fileName, string searchString, ref int progress, ref StringBuilder sb, ref StringBuilder res1)
{
bool checkNextLine=false;
using (var file = File.OpenText(fileName))
{
int i = 0;
while (!file.EndOfStream)
{
i++;
var line = file.ReadLine();
progress = (int)file.BaseStream.Position;
if (line.Contains(searchString))
{
sb.AppendFormat("Deleting(row {0}):\n{1}\n", (i), line);
checkNextLine = true;
}
else
{
if (cbDB && checkNextLine && line.StartsWith(" "))
{
sb.AppendFormat("{0}\n", line);
}
else
{
checkNextLine = false;
res1.AppendLine(line);
}
}
}
}
sb.AppendLine("\n...Deleting finished!);
}
I'm trying to let a program post a bunch of text. The user enters text, the amount of messages and how fast these must be delivered. While the program is busy, the button text needs to be "Stop" instead of "Start". When you press the button to force it to stop after you've initially launched it, the text changes back to "Start", but this doesn't happen when the program stops after the given amount of messages are delivered, even though the code is in place and doesn't generate an error.
I have a feeling that this is because of the text not updating for some reason. I've tried to flush it with Invalidate() and Update(), but this isn't working. How to fix this?
Here is the code:
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "Start")
{
isEvil = true;
button1.Text = "Stop";
Thread t = new Thread(StartTyping);
t.Start(textBox1.Text);
}
else
{
isEvil = false;
button1.Text = "Start";
}
}
private void StartTyping(object obj)
{
string message = obj.ToString();
int amount = (int)numericUpDown2.Value;
Thread.Sleep(3000);
for (int i = 0; i < amount; i++)
{
if (isEvil == false)
{
//////This does NOT work
//button1.Text = "Start";
//button1.Invalidate();
//button1.Update();
//button1.Refresh();
//Application.DoEvents();
break;
}
SendKeys.SendWait(message + "{ENTER}");
int j = (int)numericUpDown1.Value * 10;
Thread.Sleep(j);
}
}
You have four answers telling you to update UI stuff from the UI thread, but none of them address the logic flow problem with your code.
The reason why it doesn't happen is because it only happens in the for-loop when isEvil is false. When does isEvil get set to false? Only when you click "Stop", and nowhere else.
If you want the button to go back to "Start" after the thread finishes, without clicking "Stop", then you need to add code after the loop to do that, independent of the value of isEvil: (piggybacking off of VoidMain's answer)
private void StartTyping(object obj)
{
string message = obj.ToString();
int amount = (int)numericUpDown2.Value;
Thread.Sleep(3000);
for (int i = 0; i < amount; i++)
{
if (isEvil == false)
{
if (button1.InvokeRequired)
{
button1.BeginInvoke( new Action(() => { button1.Text = "Start"; }) );
}
else
{
button1.Text = "Start";
}
break;
}
SendKeys.SendWait(message + "{ENTER}");
int j = (int)numericUpDown1.Value * 10;
Thread.Sleep(j);
}
if (button1.InvokeRequired)
{
button1.BeginInvoke( new Action(() => { button1.Text = "Start"; }) );
}
else
{
button1.Text = "Start";
}
}
Now you have duplicated code, so you might want to split it off into a separate method.
You need to be on the UI thread to update the UI.
Try something called the SynchronizationContext. There are plenty of examples when you google it.
If you're in WPF or Silverlight, you could use the Dispatcher. Again, lots of examples if you search those keywords in google or StackOverflow.
You must update your controls from the UI thread. This is how you would do it for winforms.
for (int i = 0; i < amount; i++)
{
if (isEvil == false)
{
button1.Invoke(new Action(() => button1.Text = "Start"));
break;
}
SendKeys.SendWait(message + "{ENTER}");
int j = (int)numericUpDown1.Value * 10;
Thread.Sleep(j);
}
This will block till button1 get's its text updated. If you don't want it to block, replace Invoke with BeginInvoke
Your best bet is to use a BackgroundWorker. It's a bit too wieldy to add a concise example here but there's a decent tutorial from O'Reilly
Something like this (not tested) should work:
private void StartTyping(object obj)
{
string message = obj.ToString();
int amount = (int)numericUpDown2.Value;
Thread.Sleep(3000);
for (int i = 0; i < amount; i++)
{
if (isEvil == false)
{
if(button1.InvokeRequired)
{
button1.BeginInvoke( new Action(() => { button1.Text = "Start"; }) );
}
else
{
button1.Text = "Start";
}
break;
}
SendKeys.SendWait(message + "{ENTER}");
int j = (int)numericUpDown1.Value * 10;
Thread.Sleep(j);
}
}
I am trying to learn Threading in .Net.
Many of you must have seen this:
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(loop));
t.Start();
}
private void loop()
{
for (int i = 0; i < 100000; i++)
{
textBox1.Text = i.ToString();
}
}
It works fine, but what if my loop method has parameters in it, like:
private void loop(string str)
{
for (int i = 0; i < 100000; i++)
{
textBox1.Text = i + str;
}
}
Then how to call this method in my ThreadStart as ThreadStart accepts just the method name. Then how to call loop method in a different thread?
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start("Hello world");
private void loop(object obj)
{
string str = (string)obj;
for (int i = 0; i < 100000; i++)
{
// Don't do this: you can't change a control from another thread. Danger Will Robinson!
textBox1.Text = i + str;
}
}
Note that the loop method must accept an object parameter, so you'll have to upcast the object to your type. If you don't want, you can use a closure and an anonymous method:
string str = "Hello world";
Thread t = new Thread(() => {
for (int i = 0; i < 100000; i++)
{
// Don't do this: you can't change a control from another thread. Danger Will Robinson!
textBox1.Text = i + str;
}
});
t.Start();
In this way the anonymous method will "close" around str and it will be similar as if you had passed the parameter. Similar because there are differences/problems on closing variables. In reality I would write something similar to:
string str = "Hello world";
{
string str2 = str;
Thread t = new Thread(() => {
for (int i = 0; i < 100000; i++)
{
// Don't do this: you can't change a control from another thread. Danger Will Robinson!
textBox1.Text = i + str2;
}
});
t.Start();
}
so that no one else can "touch" str2.
If you need I can find some answer on SO that explain this "problem"
You'd use ParameterizedThreadStart instead: http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start("Foo");
// Note the use of Object here to match the delegate signature
private void loop(Object state)
{
var str = state as String;
for (int i = 0; i < 100000; i++)
{
// For what it is worth, this is illegal:
// textBox1.Text = i + str;
// You need to Invoke back to the UI thread to access a control's properties:
textBox1.Invoke(()=> { textBox1.Text = i + str; });
}
}
There is a ParameterizedThreadStart class that Delegates with a single parameter can be cast to when instantiating a Thread:
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(loop));
t.Start(str);
}
private void loop(string str)
{
for (int i = 0; i < 100000; i++)
{
//the code you had is a no-no when you are multithreading;
//all UI updates must occur on the main thread
//textBox1.Text = i + str;
UpdateTextBoxText(textBox1, i+str);
}
}
private void UpdateTextBoxText(TextBox textBox, string text)
{
//the method will invoke itself on the main thread if it isn't already running there
if(InvokeRequired)
{
this.Invoke((MethodInvoker)(()=>UpdateTextBoxText(TextBox textBox, string text)));
return;
}
textBox.Text = text;
}
If you don't need very fine-grained control over when the thread starts and stops, you can leave it to the ThreadPool and use Delegate.BeginInvoke:
private void button1_Click(object sender, EventArgs e)
{
Action<string> method = loop;
method.BeginInvoke(str, null, null);
}
private void loop(string str)
{
for (int i = 0; i < 100000; i++)
{
//textBox1.Text = i + str;
UpdateTextBoxText(textBox1, i+str);
}
}
private void UpdateTextBoxText(TextBox textBox, string text)
{
//the method will invoke itself on the main thread if it isn't already running there
if(InvokeRequired)
{
this.Invoke((MethodInvoker)(()=>UpdateTextBoxText(textBox, text)));
return;
}
textBox.Text = text;
}
Like this:
new Thread(() => loop("MyString")).Start();
You don't even have to mess with ThreadStart/ParameterizedThreadStart.
Take a look at ParameterizedThreadStart, it allows you to pass parameters into your thread start function.