Für .NET 2.0 ist hier ein netter Code, den ich geschrieben habe, der genau das tut, was Sie wollen, und der für jede Eigenschaft auf einem funktioniert 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 });
}
}
Nennen Sie es so:
// thread-safe equivalent of
// myLabel.Text = status;
SetControlPropertyThreadSafe(myLabel, "Text", status);
Wenn Sie .NET 3.0 oder höher verwenden, können Sie die obige Methode als Erweiterungsmethode der Control
Klasse umschreiben , wodurch der Aufruf von:
myLabel.SetPropertyThreadSafe("Text", status);
UPDATE 10.05.2010:
Für .NET 3.0 sollten Sie diesen Code verwenden:
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 });
}
}
die LINQ- und Lambda-Ausdrücke verwendet, um eine viel sauberere, einfachere und sicherere Syntax zu ermöglichen:
myLabel.SetPropertyThreadSafe(() => myLabel.Text, status); // status has to be a string or this will fail to compile
Der Eigenschaftsname wird jetzt nicht nur zur Kompilierungszeit überprüft, sondern auch der Typ der Eigenschaft. Daher ist es unmöglich, einer booleschen Eigenschaft (beispielsweise) einen Zeichenfolgenwert zuzuweisen und damit eine Laufzeitausnahme auszulösen.
Leider hindert dies niemanden daran, dumme Dinge zu tun, wie z. B. das Control
Eigentum und den Wert eines anderen weiterzugeben. Daher wird Folgendes gerne kompiliert:
myLabel.SetPropertyThreadSafe(() => aForm.ShowIcon, false);
Daher habe ich die Laufzeitprüfungen hinzugefügt, um sicherzustellen, dass die übergebene Eigenschaft tatsächlich zu der Eigenschaft gehört, auf die Control
die Methode aufgerufen wird. Nicht perfekt, aber immer noch viel besser als die .NET 2.0-Version.
Wenn jemand weitere Vorschläge zur Verbesserung dieses Codes für die Sicherheit beim Kompilieren hat, kommentieren Sie dies bitte!