2011-01-28 91 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