跨线程UI组件调用

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

我应该使用新的属性名称,例如“EditValueThreadSafe”而不是覆盖“EditValue”吗? 我不认为EditValue的实现发生了变化,因为无论如何调用基本属性。

namespace MyApplication.Components { using System.Windows.Forms; ///  /// Thread-safe implementation of the DevExpress.XtraEditors.ComboBoxEdit class. ///  public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit { ///  /// Gets or sets the edit value. ///  /// The edit 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); } } } ///  /// Sets the edit value. ///  /// The value. private void SetEditValue(object value) { base.EditValue = value; } } } 

您还可以委托另一个执行该工作的方法,并且在该方法中,如果在错误的线程上(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()generics类来消除创建显式委托类的需要…

  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(SetValue), // calls itself, but on correct thread new object[] { value }); else base.editValue = value; } 

}

这是线程安全的,是的,但要警惕覆盖一个属性并从根本上改变行为。 更改实现很好,但此属性现在表现得非常不同,消除了特定exception的可能性,但引入了可能的死锁或阻塞条件,这会影响调用代码。

所以,是的,这是正确使用InvokeRequired和Invoke,但我建议创建一个单独的,特定于目的和线程安全的属性,这样做是通告的。

我的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)。

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