I found the answere in a similar thread:
How do I update the GUI from another thread?
I expanded upon it with this custom class that extends System.Windows.Forms.Control
object with SetPropertyThreadSafe
and GetPropertyThreadSafe
.
To use this extention, all you have to do is to include the namespace like so:
using ControlExtention;
Here is my code:
using System;
using System.Linq.Expressions;
using System.Windows.Forms;
namespace ControlExtention
{
public static class ControlExtentions
{
// https://stackoverflow.com/questions/661561/how-do-i-update-the-gui-from-another-thread
// Usage: myLabel.SetPropertyThreadSafe(() => myLabel.Text, status); // status has to be a string or this will fail to compile
private delegate void SetPropertyThreadSafeDelegate<TResult>(Control @this, Expression<Func<TResult>> property, TResult value);
/// <summary>
/// Set property from a Thread other than the UI Thread safely.
/// Use with Lambda-Expression: ControlObject.SetPropertyThreadSafe(() => ControlObject.Property, NewPropertyValue);
/// </summary>
/// <typeparam name="TResult">Do not set.</typeparam>
/// <param name="this">Use lambda expression.</param>
/// <param name="property">Use lambda expression.</param>
/// <param name="value">Use lambda expression.</param>
public static void SetPropertyThreadSafe<TResult>(this Control @this, Expression<Func<TResult>> property, TResult value)
{
System.Reflection.PropertyInfo propertyInfo = (property.Body as MemberExpression).Member as System.Reflection.PropertyInfo;
// check ob property überhaupt ein teil von this ist
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, System.Reflection.BindingFlags.SetProperty, null, @this, new object[] { value });
}
}
private delegate TResult GetPropertyThreadSafeDelegate<TResult>(Control @this, Expression<Func<TResult>> property);
/// <summary>
/// Get property from a Thread other than the UI Thread safely.
/// Use with Lambda-Expression: value = ControlObject.GetPropertyThreadSafe(() => ControlObject.Property);
/// </summary>
/// <typeparam name="TResult">Do not set.</typeparam>
/// <param name="this">Use lambda expression.</param>
/// <param name="property">Use lambda expression.</param>
/// <param name="value">Use lambda expression.</param>
public static TResult GetPropertyThreadSafe<TResult>(this Control @this, Expression<Func<TResult>> property)
{
System.Reflection.PropertyInfo propertyInfo = (property.Body as MemberExpression).Member as System.Reflection.PropertyInfo;
// check ob property überhaupt ein teil von this ist
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)
{
return (TResult)@this.Invoke(new GetPropertyThreadSafeDelegate<TResult>(GetPropertyThreadSafe), new object[] { @this, property });
}
else
{
return (TResult)@this.GetType().InvokeMember(propertyInfo.Name, System.Reflection.BindingFlags.GetProperty, null, @this, new object[] { });
}
}
}
}