3

これはクロススレッド操作を処理する適切な方法ですか?

「EditValue」をオーバーライドする代わりに、「EditValueThreadSafe」のような新しいプロパティ名を使用する必要がありますか? 基本プロパティは関係なく呼び出されるため、EditValue の実装の変更に問題はないと思います。

namespace MyApplication.Components
{
    using System.Windows.Forms;

    /// <summary>
    /// Thread-safe implementation of the DevExpress.XtraEditors.ComboBoxEdit class.
    /// </summary>
    public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
    {
        /// <summary>
        /// Gets or sets the edit value.
        /// </summary>
        /// <value>The edit value.</value>
        public override object EditValue
        {
            get
            {
                return base.EditValue;
            }

            set
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(new MethodInvoker(delegate
                    {
                        this.SetEditValue(value);
                    }));
                }
                else
                {
                    this.SetEditValue(value);
                }
            }
        }

        /// <summary>
        /// Sets the edit value.
        /// </summary>
        /// <param name="value">The value.</param>
        private void SetEditValue(object value)
        {
            base.EditValue = value;
        }
    }
}
4

4 に答える 4

2

作業を行う別のメソッドに委任することもできます。そのメソッドで、間違ったスレッド上にある場合 (BeginInvoke が true を返す)、同じメソッドを再度呼び出します。これにより、コードを複製する必要がなくなります。

public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit    
{       
   public override object EditValue        
   {            
       get            
       {                             
            return base.EditValue;            
       }            
       set  
       {                
         SetValue(value);
       }
   }



    private void delegate SetValueDlg(object valeu);
    private void SetValue(object value)
    {
        if (this.InvokeRequired)
             this.BeginInvoke(
                 (SetValueDlg)SetValue,  // calls itself, but on correct thread
                 new object[] { value });
        else

              base.editValue = value;  

    }
}

Action() ジェネリック クラスを使用して、明示的なデリゲート クラスを作成する必要をなくすこともできます...

   public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit    
{       
   public override object EditValue        
   {            
       get {  return base.EditValue;   }            
       set { SetValue(value); }
   }

   private void SetValue(object value)
   {
       if (this.InvokeRequired)
           this.BeginInvoke(
               new Action<object>(SetValue),  // calls itself, but on correct thread
               new object[] { value });
       else                
              base.editValue = value;  

   }

}

于 2009-09-08T17:21:19.983 に答える
1

はい、スレッドセーフですが、プロパティをオーバーライドして動作を根本的に変更することには注意してください。実装の変更は問題ありませんが、このプロパティの動作は大きく異なり、特定の例外の可能性はなくなりますが、呼び出し元のコードに影響を与える可能性のあるデッドロックまたはブロック状態が導入されます。

はい、これは InvokeRequired と Invoke の正しい使用法ですが、そのように宣伝されている、目的に特化したスレッドセーフなプロパティを個別に作成することをお勧めします。

于 2009-09-08T17:25:56.463 に答える
0

あなたのような私の UI メソッドは、次のようになります。

public void setStatusLabelText(String s)
    {
        if (footerStatusLabel.InvokeRequired) {
            StringUpdateInvokeDelegate callback = new StringUpdateInvokeDelegate(setStatusLabelText);
            this.Invoke(callback, new object[] { s });
        }
        else {
            this.footerStatusLabel.Text = s;
        }            
    }

(これは、最近の .net では古いかもしれませんが、ポイントは、既に適切なスレッドにいる場合は、このメソッド内で操作を実行できるということです。これにより、読むのが少しイライラしなくなりますが、Java と比較するとまだ面倒です。 IMO)。

于 2009-09-08T17:26:39.940 に答える
0

ここに 2 セントを投入します。InvokeRequired/BeginInvoke/Invoke への実際の呼び出しは、完全にスレッド セーフではありません。(クロススレッド WinForm イベント処理での Invoke/BeginInvoke の問題の回避を参照してください。 ) これらの呼び出しを単一の場所、ユーティリティ API、拡張メソッドなどに分離する方法を見つけることをお勧めします。上記の記事には、デリゲートをラップしてスレッドセーフな動作を提供するクラスの完全なコードがあります。

于 2009-09-08T22:10:09.867 に答える