一尘不染

如何从另一个线程更新GUI?

c#

Label从另一个更新a的最简单方法是Thread什么?

  • Form正在上运行thread1,然后从中启动另一个线程(thread2)。

  • thread2处理某些文件时,我想用的工作状态更新Label上的。Form``thread2

我该怎么办?


阅读 249

收藏
2020-05-19

共1个答案

一尘不染

对于.NET 2.0,这是我编写的大量代码,完全可以实现您想要的功能,并且可以用于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 });
  }
}

这样称呼它:

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

如果您使用的是.NET 3.0或更高版本,则可以将上述方法重写为Control该类的扩展方法,从而将调用简化为:

myLabel.SetPropertyThreadSafe("Text", status);

2010年5月10日更新:

对于.NET 3.0,您应该使用以下代码:

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 });
  }
}

它使用LINQ和lambda表达式允许更简洁,更简单和更安全的语法:

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

现在不仅在编译时检查属性名称,而且属性的类型也是如此,因此不可能(例如)为布尔型属性分配字符串值,从而导致运行时异常。

不幸的是,这并不能阻止任何人做愚蠢的事情,例如传递另一个Control人的财产和价值,所以下面的代码会很高兴地被编译:

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

因此,我添加了运行时检查,以确保传递的属性确实属于Control调用该方法的属性。虽然不完美,但仍比.NET 2.0版本好很多。

如果有人对如何提高此代码的编译时安全性有任何进一步的建议,请发表评论!

2020-05-19