3

这是处理跨线程操作的适当方式吗?

我应该使用新的属性名称,例如“EditValueThreadSafe”而不是覆盖“EditValue”吗?我认为 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 相比仍然很烦人,国际海事组织)。

于 2009-09-08T17:26:39.940 回答
0

我将在这里注入我的 2 美分。对 InvokeRequired/BeginInvoke/Invoke 的实际调用并不完全是线程安全的。(请参阅在跨线程 WinForm 事件处理中避免 Invoke/BeginInvoke 的麻烦?)我建议找到某种方法来隔离对这些调用的单个位置、实用程序 api、扩展方法等。在上面的文章中,有一个类的完整代码,它包装了一个委托以提供线程安全的行为。

于 2009-09-08T22:10:09.867 回答