You will get following error when you try to update a windows form control from a separate thread.
“Cross-thread operation not valid: Control ‘progressBar1’ accessed from a thread other than the thread it was created on.”
This article guides you on how to overcome this problem.
Problem
To reproduce this error, insert a progress bar control (progressbar1) on your form and insert a button(btnStart).
{codecitation class=”brush:csharp”}
private void btnStart_Click(object sender, EventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
System.Threading.Thread t1 = new System.Threading.Thread(startProgress);
t1.Start();
}
void startProgress()
{
for (int i = 0; i {
progressBar1.Value = i; //You will get error at this line
System.Threading.Thread.Sleep(100);
}
}
{/codecitation}
Solution
{codecitation class=”brush:csharp”}
private void btnStart_Click(object sender, EventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100; System.Threading.Thread t1 = new System.Threading.Thread(startProgress);
t1.Start();
}
void startProgress()
{
for (int i = 0; i {
SetControlPropertyValue(progressBar1, “value”, i); //This is a thread safe method
System.Threading.Thread.Sleep(100);
}
}
{/codecitation}
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100; System.Threading.Thread t1 = new System.Threading.Thread(startProgress);
t1.Start();
}
void startProgress()
{
for (int i = 0; i {
SetControlPropertyValue(progressBar1, “value”, i); //This is a thread safe method
System.Threading.Thread.Sleep(100);
}
}
{/codecitation}
Note how SetControlpropertyValue function is used above. Following is it’s definition.
{codecitation class=”brush:csharp”}
delegate void SetControlValueCallback(Control oControl, string propName, object propValue);
private void SetControlPropertyValue(Control oControl, string propName, object propValue)
{
if (oControl.InvokeRequired)
{
SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
oControl.Invoke(d, new object[] { oControl, propName, propValue });
}
else
{
Type t = oControl.GetType();
PropertyInfo[] props = t.GetProperties();
foreach (PropertyInfo p in props)
{
if (p.Name.ToUpper() == propName.ToUpper())
{
p.SetValue(oControl, propValue, null);
}
}
}
}
{/codecitation}
private void SetControlPropertyValue(Control oControl, string propName, object propValue)
{
if (oControl.InvokeRequired)
{
SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
oControl.Invoke(d, new object[] { oControl, propName, propValue });
}
else
{
Type t = oControl.GetType();
PropertyInfo[] props = t.GetProperties();
foreach (PropertyInfo p in props)
{
if (p.Name.ToUpper() == propName.ToUpper())
{
p.SetValue(oControl, propValue, null);
}
}
}
}
{/codecitation}
You can apply same solution to any windows control. All you have to do is, copy SetControlValueCallback delegate and SetControlPropertyValue function from above code. For example if you want to set property of a label, use SetControlPropertyValue function.
SetControlPropertyValue(Label1, “Text”, i.ToString());
Make sure you supply property value in correct type. In above example Text is a string property. This is why I am converting variable i to string.
{kunena_discuss:20}