1. ホーム
  2. c#

[解決済み] 他のスレッドからGUIを更新するにはどうすればよいですか?

2022-02-17 22:26:18

質問事項

を更新する最も簡単な方法はどれですか? Label から別の Thread ?

  • を持っています。 Form で実行されている thread1 で、そこから別のスレッドを立ち上げています( thread2 ).

  • 一方 thread2 を更新したいと思います。 Label の上に Form の現在のステータスと thread2 の仕事です。

どうしたらいいんだろう?

どのように解決するのですか?

.NET 2.0では、私が書いたちょっとしたコードで、あなたが望むことを正確に行うことができます。 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年10月5日に更新しました。

.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 ||
      [email protected]().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 とラムダ式を使用して、よりクリーンでシンプルかつ安全な構文を可能にします。

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

コンパイル時にプロパティ名だけでなく、プロパティの型もチェックされるようになったので、例えばbooleanプロパティに文字列値を代入して実行時例外を発生させることはできなくなったのです。

残念なことに、これによって誰かが別の Control のプロパティと値で、以下のようにコンパイルされます。

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

したがって、私は渡されたプロパティが実際に Control メソッドが呼び出される。完璧ではありませんが、.NET 2.0バージョンよりはずっとましです。

もし、このコードをコンパイル時の安全性のためにさらに改善する方法があれば、ぜひコメントください。