Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>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 <code>Control</code>:</p> <pre><code>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 }); } } </code></pre> <p>Call it like this:</p> <pre><code>// thread-safe equivalent of // myLabel.Text = status; SetControlPropertyThreadSafe(myLabel, "Text", status); </code></pre> <p>If you're using .NET 3.0 or above, you could rewrite the above method as an extension method of the <code>Control</code> class, which would then simplify the call to:</p> <pre><code>myLabel.SetPropertyThreadSafe("Text", status); </code></pre> <p><strong>UPDATE 05/10/2010:</strong></p> <p>For .NET 3.0 you should use this code:</p> <pre><code>private delegate void SetPropertyThreadSafeDelegate&lt;TResult&gt;( Control @this, Expression&lt;Func&lt;TResult&gt;&gt; property, TResult value); public static void SetPropertyThreadSafe&lt;TResult&gt;( this Control @this, Expression&lt;Func&lt;TResult&gt;&gt; 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&lt;TResult&gt; (SetPropertyThreadSafe), new object[] { @this, property, value }); } else { @this.GetType().InvokeMember( propertyInfo.Name, BindingFlags.SetProperty, null, @this, new object[] { value }); } } </code></pre> <p>which uses LINQ and lambda expressions to allow much cleaner, simpler and safer syntax:</p> <pre><code>myLabel.SetPropertyThreadSafe(() =&gt; myLabel.Text, status); // status has to be a string or this will fail to compile </code></pre> <p>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.</p> <p>Unfortunately this doesn't stop anyone from doing stupid things such as passing in another <code>Control</code>'s property and value, so the following will happily compile:</p> <pre><code>myLabel.SetPropertyThreadSafe(() =&gt; aForm.ShowIcon, false); </code></pre> <p>Hence I added the runtime checks to ensure that the passed-in property does actually belong to the <code>Control</code> that the method's being called on. Not perfect, but still a lot better than the .NET 2.0 version.</p> <p>If anyone has any further suggestions on how to improve this code for compile-time safety, please comment!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload