How to call a control method from another thread - c#

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.

Related

event properties change does not trigger

So i have created an event, whenever the property ActualVoltage changed, it will update in Form1 but it doesnt. Property ActualVoltage change, when i send a set-voltage command to the machine, then it will send back a number and i assign that number to AcutalVoltage. pls help me, pls show me where is my mistake and explain it for me like i am a 5 years old kid.Here is my event code:
public delegate void ValueChange();
public event ValueChange Change;
public double ActualVoltage
{
get { return actualVoltage; }
set
{
if (actualVoltage == value) return;
else
{
actualVoltage = value;
OnValueChange();
}
}
}
private void OnValueChange()
{
Change?.Invoke();
}
in Form1:
private void Form1_Load(object sender, EventArgs e)
{
ps.Change += ps_change;
}
private void ps_change()
{
lblValueActualVoltage.Text = ps.ActualVoltage.ToString();
lblValueActualCurrent.Text = ps.ActualCurrent.ToString();
lblHexCur.Text = ps.HexActualCurrent1;
lblHexVol.Text = ps.HexActualVoltage1;
}
updated: in class PS2000B
public void GetDeviceStatusInformation(byte[] rawData)
{
remoteMode = ((byte)(rawData[0] & 0b1)).ToString();
outputMode = ((byte)(rawData[1] & 0b1)).ToString();
List<byte> temp = new List<byte>();
foreach (var v in rawData)
temp.Add(v);
byte[] vontageBytes = temp.GetRange(2, 2).ToArray();
HexActualVoltage = BitConverter.ToString(vontageBytes);
Array.Reverse(vontageBytes);
byte[] currentBytes = temp.GetRange(4, 2).ToArray();
HexActualCurrent = BitConverter.ToString(currentBytes);
Array.Reverse(currentBytes);
var a = (BitConverter.ToInt16(vontageBytes, 0));
ActualVoltage =Math.Round( BitConverter.ToInt16(vontageBytes, 0) * nominalVoltage / 25600.0,2);
ActualCurrent = BitConverter.ToInt16(currentBytes, 0) * nominalCurrent / 25600.0;
}
public void RunTest(string safeFileName,string save)
{
Stopwatch st = new Stopwatch();
List<string> timeMeasure = new List<string>();
List<string> CurrentResults = new List<string>();
List<int> Time = new List<int>();
List<string> Voltage = new List<string>();
FileStream file = new FileStream(safeFileName, FileMode.Open, FileAccess.Read);
StreamReader reader = new StreamReader(file);
string strRead = reader.ReadLine();
while (strRead != null)
{
string[] temp = strRead.Split(';');
Voltage.Add(temp[0]);
Time.Add(int.Parse(temp[1]));
strRead = reader.ReadLine();
}
reader.Close();
file.Close();
int n = 0;
st.Start();
for (int i = 0; i < Voltage.Count(); i++)
{
SetVoltage(Voltage[i]);
for (int j = 0; j < Time[i]/300; j++)
{
UpdateStatusInfomationAndActualValue();
CurrentResults.Add(Voltage[i]+";"+0.3*n+";"+ActualCurrent.ToString()+";"+ HexActualCurrent);
n++;
}
}
st.Stop();
FileStream wfile = new FileStream(save +"\\results.txt", FileMode.Create, FileAccess.Write);
StreamWriter writer = new StreamWriter(wfile);
writer.WriteLine("VOlTAGE;TIME;CURRENT");
foreach (var v in CurrentResults)
writer.WriteLine(v);
writer.WriteLine("TOTAL TIME: "+st.Elapsed);
writer.Close();
wfile.Close();
}
public void SetVoltage(string vol)
{
vol = vol.Replace('.', ',');
ToPowerSupply ToPowerSupply = new ToPowerSupply();
var b = Convert.ToInt16(Single.Parse(vol) * 25600 / nominalVoltage);
var input = BitConverter.GetBytes(b);
Array.Reverse(input);
var temp = ToPowerSupply.SendCommand(0b11, ObjectList.SET_U, input, 2);
ComPort.Write(temp, 0, temp.Count());
Thread.Sleep(150);
int bytes = ComPort.BytesToRead;
byte[] rawData = new byte[bytes];
ComPort.Read(rawData, 0, bytes);
}
Following Form1.cs handles events properly:
public delegate void ValueChange();
public event ValueChange Change;
private double actualVoltage;
public double ActualVoltage
{
get { return actualVoltage; }
set
{
if (actualVoltage == value) return;
else
{
actualVoltage = value;
OnValueChange();
}
}
}
private void ps_change()
{
//UI updates here
}
private void OnValueChange()
{
Change?.Invoke();
}
private void Form1_Load(object sender, EventArgs e)
{
Change += ps_change;
}
Please note: If your property setters are invoked in non-GUI-thread, then you should marshal GUI-updating code to UI thread as mentioned here
If property setter is invoked on a non-GUI thread, the ps_change method should be as follows:
private void ps_change()
{
if (InvokeRequired)
{
BeginInvoke(new Action(ps_change));
return;
}
lblValueActualVoltage.Text = ps.ActualVoltage.ToString();
lblValueActualCurrent.Text = ps.ActualCurrent.ToString();
lblHexCur.Text = ps.HexActualCurrent1;
lblHexVol.Text = ps.HexActualVoltage1;
}
Why?
i call the properties setter not on the GUI thread.
Controls on the form cannot be manipulated from a non-GUI thread. This is because Windows Forms controls are bound to Windows handles, and Windows handles are owned by threads. If a control (Form or Label in this case) is created on one thread (most likely the main application thread), operations on its handle (e.g. changing the text) cannot be performed on a different thread.
To resolve this, the Control class has methods InvokeRequired, Invoke, and BeginInvoke:
InvokeRequired indicates whether the control belongs to a different thread (true) or to the current thread (false).
When InvokeRequired is true, either Invoke or BeginInvoke must be used. Both these methods marshal another delegate to the GUI thread that owns the control. All control manipulations must be performed from that delegate.
The difference between the two methods is that Invoke blocks the calling thread until the delegate is executed on the GUI thread, whereas BeginInvoke just submits invocation to the queue and returns immediately. The marshaling is performed by a special Windows message sent to a window message queue.
More info here: https://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired(v=vs.110).aspx
The usual pattern of implementing this is check InvokeRequired inside an event handler, and if it's true, call either Invoke or BeginInvoke and supply delegate to this same event handler again. The handler is then re-invoked on the GUI thread, where InvokeRequired is false, and then the code safely manipulates form controls.
I finally figure out the reason. I use Thread.Sleep() on main thread. At the time ActualVoltage changes, the main thread is sleeping, thats why the GUI does not update. To handle this, i use BackGroudWorker and everything is fine now.

How can I report multiple reportprogress values from backgroundworker dowork event to a dataGridView?

Added this class:
public class MyProgress
{
public string Id { get; set; }
public string Progress { get; set; }
}
The dowork event:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if ((worker.CancellationPending == true))
{
e.Cancel = true;
}
else
{
List<IntPtr> intptrs = GetProcessesIntptrList();
for (int x = 0; x < intptrs.Count ; x++)
{
GetProcessInfo(intptrs[x]);
}
while (true)
{
List<MyProgress> prog = new List<MyProgress>();
prog = new List<MyProgress>();
procList = Process.GetProcesses().ToList();
for (int i = 0; i < procList.Count; i++)
{
Process[] processes = Process.GetProcessesByName(procList[i].ProcessName);
PerformanceCounter performanceCounter = new PerformanceCounter();
performanceCounter.CategoryName = "Process";
performanceCounter.CounterName = "Working Set - Private";//"Working Set";
performanceCounter.InstanceName = processes[0].ProcessName;
prog.Add(new MyProgress { Id = procList[i].ProcessName, Progress = ((uint)performanceCounter.NextValue() / 1024).ToString("N0") });
worker.ReportProgress(0, prog);
}
}
}
}
And last the backgroundworker progresschanged event where I want to add the values of each process to the datagridview1 rows under cell 3.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
foreach (MyProgress p in (e.UserState as List<MyProgress>))
{
currentRow.Cells[3].Value = p.Progress;
dataGridView1.Rows.Add(
p.Progress);
}
}
The variable currentRow not exist yet. And I know that cell 3 is where I want to add all the rows of the processes values.
And I also don't know how many rows there should be.
And how to do the reporting of each process value to a row under cell 3 ?
I tried this in the progresschanged event:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
foreach (MyProgress p in (e.UserState as List<MyProgress>))
{
int rowIdx = dataGridView1.Rows.Add();
dataGridView1.Rows[rowIdx].Cells[3].Value = p.Progress;
}
}
But i'm getting exception on the foreach:
The exception is:
Additional information: Collection was modified; enumeration operation may not execute.
System.InvalidOperationException was unhandled by user code
HResult=-2146233079
Message=Collection was modified; enumeration operation may not execute.
Source=mscorlib
StackTrace:
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at Automation.Form1.backgroundWorker1_ProgressChanged(Object sender, ProgressChangedEventArgs e) in d:\C-Sharp\Automation\Automation\Automation\Form1.cs:line 719
InnerException:
As far as I understand your question, you need this
Integer rowIdx = dataGridView1.Rows.Add();
dataGridView1.Rows[rowIdx].Cells[3].Value = p.Progress
Why error? - This is because you have design flaw - in backgroundWorker1_DoWork, which runs on background thread, you still modifying collection, which you at the same time passing to progress event. What happens, is while you iterating it on one thread, another thread adds items. What you need to do is make a copy, pass this copy and iterate this copy. Here is one simple way to do it with array
. . . .
MyProgress[] arrP;
prog.CopyTo(arrP);
worker.ReportProgress(0, arrP);
. . .
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
MyProgress[] progArr = (MyProgress[])e.UserState;
foreach (MyProgress p in progArr)
{
int rowIdx = dataGridView1.Rows.Add();
dataGridView1.Rows[rowIdx].Cells[3].Value = p.Progress;
}
}
I am not sure about this whole design, so I am not trying to change it. Just saying what is wrong now, not in general.

require some sort of loop or jumping statement for my code

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();
}
}

using the Background Worker in C#?

One part of my application works loading of Images from the predefined folder. At this time when loading the images it takes more time. Now I figured out that the progress Bar which can let me to tell the progress of loading.
The Problem I faced is:
I can't able to Integrate the BackgroudWorker, Progress Bar with my function.
For Instance the following is the Background worker and Progress bar code:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Load file list here
int totalImageCount = 10000;
// Set maximum value of the progress bar
progressBar1.Invoke(new Action(() => { progressBar1.Maximum = totalImageCount; }));
for (int i = 0; i < totalImageCount; i++)
{
// Load a single image here
Thread.Sleep(10);
// User cancelled loading (form shut down)
if (e.Cancel) return;
// Set the progress
progressBar1.Invoke(new Action(() => { progressBar1.Value = i; }));
}
// Cleanup here
}
// Starts the loading
private void button1_Click(object sender, EventArgs e)
{
// Start loading images
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.RunWorkerAsync();
}
// Stops the loading
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// Stop the loading when the user closes the form
if (backgroundWorker1.IsBusy) backgroundWorker1.CancelAsync();
}
The following is The function which needs to be for Progress Bar
private void LoadImages()
{
string imagesPath = (Application.StartupPath + "/UnknownFaces/");
string[] extensions = new[] { ".jpg", ".jpeg", ".png" };
var allfiles = Directory.GetFiles(imagesPath);
this.imageList1.ImageSize = new Size(256, 250);
this.imageList1.ColorDepth = ColorDepth.Depth32Bit;
foreach (FileInfo fileInfo in filesSorted)
{
try
{
this.imageList1.Images.Add(fileInfo.Name,
Image.FromFile(fileInfo.FullName));
}
catch
{
Console.WriteLine(fileInfo.FullName + " is is not a valid image.");
}
}
this.lstView_un.View = View.LargeIcon;
lstView_un.LargeImageList = this.imageList1;
lstView_un.Items.Clear();
for (int j = 0; j < this.imageList1.Images.Count; j++)
{
ListViewItem item = new ListViewItem();
item.ImageIndex = j;
item.Text = imageList1.Images.Keys[j].ToString();
this.lstView_un.Items.Add(item);
}
}
catch (Exception ex)
{
MessageBox.Show("Something Wrong happen! "+ex.Message);
}
}
I think the main routine works are there:
this.lstView_un.View = View.LargeIcon;
lstView_un.LargeImageList = this.imageList1;
lstView_un.Items.Clear();
for (int j = 0; j < this.imageList1.Images.Count; j++)
{
ListViewItem item = new ListViewItem();
item.ImageIndex = j;
item.Text = imageList1.Images.Keys[j].ToString();
this.lstView_un.Items.Add(item);
}
The slow part of your code is actually the loop that reads the files, not the loop that populates your ListView.
The best way to report or otherwise present progress state in the UI from BackgroundWorker is to use the ProgressChanged event. However, the code example you are working from will work as well. That is, just update the ProgressBar object directly from your worker code. It fails to take full advantage of the features that BackgroundWorker provides (and indeed, raises the question of why bother with BackgroundWorker if you're not going to use its features), but it will work.
For example:
var allfiles = Directory.GetFiles(imagesPath);
this.imageList1.ImageSize = new Size(256, 250);
this.imageList1.ColorDepth = ColorDepth.Depth32Bit;
// Set the maximum value based on the number of files you get
progressBar1.Invoke((MethodInvoker)(() => { progressBar1.Maximum = filesSorted.Count(); }));
foreach (FileInfo fileInfo in filesSorted)
{
try
{
this.imageList1.Images.Add(fileInfo.Name,
Image.FromFile(fileInfo.FullName));
}
catch
{
Console.WriteLine(fileInfo.FullName + " is is not a valid image.");
}
// Update the ProgressBar, incrementing by 1 for each iteration of the loop
progressBar1.Invoke((MethodInvoker)(() => progressBar1.Increment(1)));
}
Note: your code example is incomplete, and doesn't make sense even as a snippet. One problem in particular is that you retrieve the file names into the array allfiles, but you are iterating on a completely different collection, filesSorted. I did my best with the code you provided to work with, but since the code you posted wouldn't work as-is, you may well have to make some minor adjustments to the example I've provided to get it to do what you want.
If you are unable to figure this out with the above, please provide a good, minimal, complete code example that reliably illustrates your scenario and what precisely you're having trouble figuring out.

Display a string character by character on textbox

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.

Categories

Resources