If you are developing with Windows Forms, you know that due to thread safety reasons you can not change any UI control’s settings from threads different from UI thread itself.
Assuming you have a multithreaded application where you want to acquire some values in parallel and then display them on the UI elements. It could be some server requests (even simultaneous requests to different servers) or just some calculations – it doesn’t really matter now. What matters is that you need to apply some values to the same controls several times (applying text to several "labels" or "text boxes").
For our simple case let’s assume the situation when you have several "labels" and "combo boxes". During application startup some calculations will be done and results will be put inside combo boxes. Each label will be marked in according to the it's calculation. As a calculation example let’s take the simple progression of "x" order. (order = 1: 1, 1, 1, 1, ...; order = 2: 2, 4, 8, 16, ...'; order = 3: 3, 9, 27, 81; etc.) The task is to calculate each sequence in a separate thread.
For somebody who doesn’t familiar with invoking, the first and naïve solution could be something like this:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsInvoking
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread t1 = new Thread(ApplyUiValues);
Thread t2 = new Thread(ApplyUiValues);
Thread t3 = new Thread(ApplyUiValues);
Thread t4 = new Thread(ApplyUiValues);
Thread t5 = new Thread(ApplyUiValues);
t1.Start(1.0);
t2.Start(2.0);
t3.Start(3.0);
t4.Start(4.0);
t5.Start(5.0);
}
private void ApplyUiValues(object order)
{
if (order is Double)
{
Double o = Convert.ToInt32(order);
string labelStr = string.Format("Order {0}", o);
List<Double> values = new List<Double>();
List<string> strings = new List<string>();
values = GenerateOneToTenSequense(order);
foreach (Double i in values)
{
strings.Add(i.ToString());
}
switch ((int)o)
{
case 1:
label1.Text = labelStr;
comboBox1.Items.AddRange(strings.ToArray());
break;
case 2:
label2.Text = labelStr;
comboBox2.Items.AddRange(strings.ToArray());
break;
case 3:
label3.Text = labelStr;
comboBox3.Items.AddRange(strings.ToArray());
break;
case 4:
label4.Text = labelStr;
comboBox4.Items.AddRange(strings.ToArray());
break;
case 5:
label5.Text = labelStr;
comboBox5.Items.AddRange(strings.ToArray());
break;
default:
break;
}
}
}
private List<Double> GenerateOneToTenSequense(object order)
{
List<Double> sequence = new List<Double>();
if (order is Double)
{
Double o = Convert.ToInt32(order);
for (Double i = 1; i <= 10; ++i)
{
sequence.Add(Math.Pow(o, i));
}
}
return sequence;
}
}
}
But once you’ll try to run this, you’ll immediately get the following exception:

InvalidOperationException – you can not change UI properties from other threads. MSDN provides a very well explanation on How to: Make Thread-Safe Calls to Windows Forms Controls
But there is something missing. For example – do I really need to call "Background Worker" for this simple things? What if I have many similar controls (like in my example) – should I repeatedly call InvokeRequired property? I just want to use the simple one line of code similar to this one:
label1.Text = labelStr;
So my solution was to create a helper class with static methods to call most often used controls:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace WindowsFormsInvoking
{
public class Invoker
{
#region delegates
delegate void SetComboBoxItemsCallback(
out bool isSet,
ComboBox invokingCtrl,
List<string> items);
delegate void SetComboBoxSelectedItemCallback(
out bool isSet,
ComboBox invokingCtrl,
int itmToSet);
delegate void TrySetLabelTextCallback(
out bool isSet,
Label invokingCtrl,
string valToSet);
#endregion
public static void LoadComboBoxItems(
Control caller,
ComboBox invokingCtrl,
List<string> items)
{
try
{
bool wasSet = false;
SetComboBoxItems(out wasSet, invokingCtrl, items);
if (!wasSet)
{
SetComboBoxItemsCallback cb =
new SetComboBoxItemsCallback(SetComboBoxItems);
caller.Invoke(cb,
new object[] { wasSet, invokingCtrl, items });
}
if (invokingCtrl.Items.Count > 0)
{
Invoker.SetComboBoxSelectedItem(
out wasSet,
invokingCtrl, 0);
if (!wasSet)
{
SetComboBoxSelectedItemCallback cb =
new SetComboBoxSelectedItemCallback(
Invoker.SetComboBoxSelectedItem);
caller.Invoke(cb,
new object[] { wasSet, invokingCtrl, 0 });
}
}
}
catch (Exception ex)
{
}
}
public static void SetLabelText(
Control caller,
Label invokingCtrl,
string valToSet)
{
try
{
bool wasSet = false;
Invoker.TrySetLabelText(out wasSet,
invokingCtrl, valToSet);
if (!wasSet)
{
TrySetLabelTextCallback cb =
new TrySetLabelTextCallback(Invoker.TrySetLabelText);
caller.Invoke(cb, new object[] { wasSet, invokingCtrl, valToSet });
}
}
catch (Exception ex)
{
}
}
private static void SetComboBoxItems(
out bool isSet,
ComboBox invokingCtrl,
List<string> items)
{
if (!invokingCtrl.InvokeRequired &&
invokingCtrl.Items.Count == 0)
{
invokingCtrl.Items.AddRange(items.ToArray());
isSet = true;
}
isSet = false;
}
private static void SetComboBoxSelectedItem(
out bool isSet,
ComboBox invokingCtrl,
int itmToSet)
{
if (!invokingCtrl.InvokeRequired)
{
invokingCtrl.SelectedItem = invokingCtrl.Items[itmToSet];
isSet = true;
}
isSet = false;
}
private static void TrySetLabelText(
out bool isSet,
Label invokingCtrl,
string valToSet)
{
if (!invokingCtrl.InvokeRequired)
{
invokingCtrl.Text = valToSet;
isSet = true;
}
isSet = false;
}
}
}
After creating the helper Invoker class I’m able to use the property assignment in one line like I wanted:
Invoker.SetLabelText(this, label1, labelStr);
And the result is:
private void ApplyUiValues(object order)
{
if (order is Double)
{
Double o = Convert.ToInt32(order);
string labelStr = string.Format("Order {0}", o);
List<Double> values = new List<Double>();
List<string> strings = new List<string>();
values = GenerateOneToTenSequense(order);
foreach (Double i in values)
{
strings.Add(i.ToString());
}
switch ((int)o)
{
case 1:
Invoker.SetLabelText(this, label1, labelStr);
Invoker.LoadComboBoxItems(this, comboBox1, strings);
break;
case 2:
Invoker.SetLabelText(this, label2, labelStr);
Invoker.LoadComboBoxItems(this, comboBox2, strings);
break;
case 3:
Invoker.SetLabelText(this, label3, labelStr);
Invoker.LoadComboBoxItems(this, comboBox3, strings);
break;
case 4:
Invoker.SetLabelText(this, label4, labelStr);
Invoker.LoadComboBoxItems(this, comboBox4, strings);
break;
case 5:
Invoker.SetLabelText(this, label5, labelStr);
Invoker.LoadComboBoxItems(this, comboBox5, strings);
break;
default:
break;
}
}
}

You can download this example code from Max's SVN :http://subversion.assembla.com/svn/max-s-blog-posts/
Please leave your comment if you found this post helpful.
Thanks and enjoy your coding! Max B.