2011-01-28 94 views
6

我有一个基类实现INotifyPropertyChangedINotifyPropertyChanged的和线程

protected void OnNotifyChanged(string pName) 
{ 
    if (PropertyChanged != null) 
    { 
     PropertyChanged(this, new PropertyChangedEventArgs(pName)); 
    } 
} 

public event PropertyChangedEventHandler PropertyChanged; 

我有一个属性Latitude派生类,像这样:

private double latitude; 

public double Latitude 
{ 
    get { return latitude; } 
    set { latitude = value; OnNotifyChanged("Latitude"); } 
} 

我的派生类中也有一个方法Fly其操纵Latitude

我也有一个形式绑定到我的派生类的Latitude一个TextBox:

txtLat.DataBindings.Clear();  
txtLat.DataBindings.Add("Text", bindSrc, "Latitude"); 

一个线程用于揭开序幕Fly像这样:

Thread tFly = new Thread(f.Fly); 
tFly.IsBackground = true; 
tFly.Start(); 

Latitude变化,一引发异常:

DataBinding cannot find a row in the list that is suitable for all bindings.

回答

8

这似乎是线程亲和力的一个奇怪问题。最终,代码尝试从非UI线程进行更新 - 我不清楚为什么它不仅仅是显示了跨线程异常,但是 - 我想知道这是否实际上是一个全面的异常处理程序。如果我删除BindingSource(并直接绑定到该对象,这是有效的),您得到一个跨线程异常(我预期)。

个人,我会倾向于手动处理这个问题,即订阅事件与执行一次Invoke到UI线程并手动更新Text的方法。不过,我如果以前的一些跨线程绑定代码可以帮助...


下面是一个使用Invoke的例子只是检查:

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows.Forms; 

class FlightUav : INotifyPropertyChanged 
{ 
    protected void OnNotifyChanged(string pName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(pName)); 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
    private double _latitude; 
    public double Latitude 
    { 
     get { return _latitude; } 
     set { _latitude = value; OnNotifyChanged("Latitude"); } 
    } 
    public void Fly() 
    { 
     for (int i = 0; i < 100; i++) 
     { 
      Latitude++; 
      Thread.Sleep(10); 
     } 
    } 
    [STAThread] 
    static void Main() 
    { 
     using (Form form = new Form()) 
     { 
      FlightUav currentlyControlledFlightUav = new FlightUav(); 

      currentlyControlledFlightUav.PropertyChanged += delegate 
      { // this should be in a *regular* method so that you can -= it when changing bindings... 
       form.Invoke((MethodInvoker)delegate 
       { 
        form.Text = currentlyControlledFlightUav.Latitude.ToString(); 
       }); 
      }; 


      using (Button btn = new Button()) 
      { 
       btn.Text = "Fly"; 
       btn.Click += delegate 
       { 
        Thread tFly = new Thread(currentlyControlledFlightUav.Fly); 
        tFly.IsBackground = true; 
        tFly.Start(); 
       }; 
       form.Controls.Add(btn); 
       Application.Run(form); 
      } 
     } 
    } 


} 

下面是一个使用(修改的例子)版本的一些旧的线程代码我的:

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows.Forms; 

class FlightUav : INotifyPropertyChanged 
{ 
    protected void OnNotifyChanged(string pName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(pName)); 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
    private double _latitude; 
    public double Latitude 
    { 
     get { return _latitude; } 
     set { _latitude = value; OnNotifyChanged("Latitude"); } 
    } 
    public void Fly() 
    { 
     for (int i = 0; i < 100; i++) 
     { 
      Latitude++; 
      Thread.Sleep(10); 
     } 
    } 
    [STAThread] 
    static void Main() 
    { 
     using (Form form = new Form()) 
     { 
      FlightUav currentlyControlledFlightUav = new FlightUav(); 
      BindingSource bindSrc = new BindingSource(); 
      var list = new ThreadedBindingList<FlightUav>(); 
      list.Add(currentlyControlledFlightUav); 
      bindSrc.DataSource = list; 

      form.DataBindings.Clear(); 
      form.DataBindings.Add("Text", list, "Latitude"); 

      using (Button btn = new Button()) 
      { 
       btn.Text = "Fly"; 
       btn.Click += delegate 
       { 
        Thread tFly = new Thread(currentlyControlledFlightUav.Fly); 
        tFly.IsBackground = true; 
        tFly.Start(); 
       }; 
       form.Controls.Add(btn); 
       Application.Run(form); 
      } 
     } 
    } 


} 
public class ThreadedBindingList<T> : BindingList<T> 
{ 
    private readonly SynchronizationContext ctx; 
    public ThreadedBindingList() 
    { 
     ctx = SynchronizationContext.Current; 
    } 
    protected override void OnAddingNew(AddingNewEventArgs e) 
    { 
     SynchronizationContext ctx = SynchronizationContext.Current; 
     if (ctx == null) 
     { 
      BaseAddingNew(e); 
     } 
     else 
     { 
      ctx.Send(delegate 
      { 
       BaseAddingNew(e); 
      }, null); 
     } 
    } 
    void BaseAddingNew(AddingNewEventArgs e) 
    { 
     base.OnAddingNew(e); 
    } 
    protected override void OnListChanged(ListChangedEventArgs e) 
    { 
     if (ctx == null) 
     { 
      BaseListChanged(e); 
     } 
     else 
     { 
      ctx.Send(delegate 
      { 
       BaseListChanged(e); 
      }, null); 
     } 
    } 
    void BaseListChanged(ListChangedEventArgs e) 
    { 
     base.OnListChanged(e); 
    } 
} 
+0

@WulfgarPro增加了两个*不同的*例子 – 2011-01-28 06:48:19