Wednesday, January 19, 2011

Silverlight/WinForm/WPF multi-threading updates the value in UI Controls

Because of thread safety, this block of code below will come out exception when updating the UI thread control values:

private void btn_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(MyFunc));
t.Start("Hello World");
}


void MyFunc(object obj)
{
this.textBox1.Text = obj.ToString();
}

The reason is because of thread safety, the UI thread doesn't allow cross thread call by default.

The way to solve this:

1. Set Control CheckForIllegalCrossThreadCalls to be false (not recommend)

public partial class Form1 : Form
{

public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}

private void btn_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(MyFunc));
t.Start("Hello World");
}


void MyFunc(object obj)
{
this.textBox1.Text = obj.ToString();
}
}

2. Use Delegate in WinForm


public partial class Form1 : Form
{

Delegate void Del(object obj);
public Form1()
{
InitializeComponent();
}

private void btn_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(MyFunc));
t.Start("Hello World");
}


void MyFunc(object obj)
{
Del del = new Del(MyFuncSetValue);
textBox1.Invoke(del,obj);
}

void MyFuncSetValue(object obj)
{
this.textBox1.Text = obj.ToString();
}
}

3. Use SynchronizationContext

see my post article:

http://jiezhu0815.blogspot.com/2009/02/about-synchronizationcontext.html

4. Use BackgroundWorker

See my post article:

http://jiezhu0815.blogspot.com/2010/11/use-backgroundworker.html
http://jiezhu0815.blogspot.com/2010/11/use-backgroundworker-2.html
http://jiezhu0815.blogspot.com/2010/11/use-backgroundworker-3.html

5 Use Control.BeginInvoke (in WinForm) or Dispatcher.BeginInvoke (in SilverLight or WPF)



public partial class Form1 : Form
{

public Form1()
{
InitializeComponent();
}

private void btn_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ParameterizedThreadStart(MyFunc));
t.Start("Hello World");
}


void MyFunc(object obj)
{
this.Dispatcher.BeginInvoke(Action(() => { this.txt.Text = text.ToString(); }));
}
}

No comments: