C# Windows Forms Application - Updating Gui from Another Thread and Class

How do I update the GUI from another thread?

For .NET 2.0, here's a nice bit of code I wrote that does exactly what you want, and works for any property on a Control:

private delegate void SetControlPropertyThreadSafeDelegate(
Control control,
string propertyName,
object propertyValue);

public static void SetControlPropertyThreadSafe(
Control control,
string propertyName,
object propertyValue)
{
if (control.InvokeRequired)
{
control.Invoke(new SetControlPropertyThreadSafeDelegate
(SetControlPropertyThreadSafe),
new object[] { control, propertyName, propertyValue });
}
else
{
control.GetType().InvokeMember(
propertyName,
BindingFlags.SetProperty,
null,
control,
new object[] { propertyValue });
}
}

Call it like this:

// thread-safe equivalent of
// myLabel.Text = status;
SetControlPropertyThreadSafe(myLabel, "Text", status);

If you're using .NET 3.0 or above, you could rewrite the above method as an extension method of the Control class, which would then simplify the call to:

myLabel.SetPropertyThreadSafe("Text", status);

UPDATE 05/10/2010:

For .NET 3.0 you should use this code:

private delegate void SetPropertyThreadSafeDelegate<TResult>(
Control @this,
Expression<Func<TResult>> property,
TResult value);

public static void SetPropertyThreadSafe<TResult>(
this Control @this,
Expression<Func<TResult>> property,
TResult value)
{
var propertyInfo = (property.Body as MemberExpression).Member
as PropertyInfo;

if (propertyInfo == null ||
!@this.GetType().IsSubclassOf(propertyInfo.ReflectedType) ||
@this.GetType().GetProperty(
propertyInfo.Name,
propertyInfo.PropertyType) == null)
{
throw new ArgumentException("The lambda expression 'property' must reference a valid property on this Control.");
}

if (@this.InvokeRequired)
{
@this.Invoke(new SetPropertyThreadSafeDelegate<TResult>
(SetPropertyThreadSafe),
new object[] { @this, property, value });
}
else
{
@this.GetType().InvokeMember(
propertyInfo.Name,
BindingFlags.SetProperty,
null,
@this,
new object[] { value });
}
}

which uses LINQ and lambda expressions to allow much cleaner, simpler and safer syntax:

// status has to be of type string or this will fail to compile
myLabel.SetPropertyThreadSafe(() => myLabel.Text, status);

Not only is the property name now checked at compile time, the property's type is as well, so it's impossible to (for example) assign a string value to a boolean property, and hence cause a runtime exception.

Unfortunately this doesn't stop anyone from doing stupid things such as passing in another Control's property and value, so the following will happily compile:

myLabel.SetPropertyThreadSafe(() => aForm.ShowIcon, false);

Hence I added the runtime checks to ensure that the passed-in property does actually belong to the Control that the method's being called on. Not perfect, but still a lot better than the .NET 2.0 version.

If anyone has any further suggestions on how to improve this code for compile-time safety, please comment!

C# Windows Forms Application - Updating GUI from another thread AND class?

Check the InvokeRequired of the Control class, and if it's true, then call the Invoke and pass in a delegate (usually an anonymous method) that does what you want to do on the client's thread.

Example:

public void DoWork(Form form)
{
if (form.InvokeRequired)
{
// We're on a thread other than the GUI thread
form.Invoke(new MethodInvoker(() => DoWork(form)));
return;
}

// Do what you need to do to the form here
form.Text = "Foo";
}

Update UI from different thread

If you use the async/await programming model, you could do this quite easily.

Instead of what you have, try something like this:

private async void myButton_Click(object sender, RoutedEventArgs e)
{
Task t = MyMethod();
await t;
}

private async Task MyMethod()
{
myTextBlock.Text = "Worked!";
}

Update WinForm Controls from another thread _and_ class

It does not matter from which class you are updating the form. WinForm controls have to be updated on the same thread that they were created on.

Hence, Control.Invoke, allows you to execute a method on the control on its own thread. This is also called asynchronous execution, since the call is actually queued up and executed separately.

Look at this article from msdn, the example is similar to your example. A separate class on a separate thread updates a list box on the Form.

----- Update
Here you do not have to pass this as a parameter.

In your Winform class, have a public delegate that can update the controls.

class WinForm : Form
{
public delegate void updateTextBoxDelegate(String textBoxString); // delegate type
public updateTextBoxDelegate updateTextBox; // delegate object

void updateTextBox1(string str ) { textBox1.Text = str1; } // this method is invoked

public WinForm()
{
...
updateTextBox = new updateTextBoxDelegate( updateTextBox1 ); // initialize delegate object
...
Server serv = new Server();

}

From the ClientConnection Object, you do have to get a reference to the WinForm:Form object.

class ClientConnection
{
...
void display( string strItem ) // can be called in a different thread from clientConnection object
{
Form1.Invoke( Form1.updateTextBox, strItem ); // updates textbox1 on winForm
}
}

In the above case, 'this' is not passed.

Update UI item from another class and thread

You should check the Invoke for UI thread

private void UpdateChat(string message)
{
if(this.InvokeRequired)
{
this.Invoke(new MethodInvoker(delegate {
lstChat.Items.Insert(lstChat.Items.Count, message);
lstChat.SelectedIndex = lstChat.Items.Count - 1;
lstCat.Refresh();
}));
} else {
lstChat.Items.Insert(lstChat.Items.Count, message);
lstChat.SelectedIndex = lstChat.Items.Count - 1;
lstCat.Refresh();
}
}

how to update a windows form GUI from another class?

You need to call the Invoke method on the form. For example:

private void someMethod() {
myOtherForm.Invoke(new MethodInvoker(delegate() {
// update things in myOtherForm here
}));
}

If you don't need the updates to be finished before returning back to the method, you should use BeginInvoke instead of Invoke.



Related Topics



Leave a reply



Submit