2011-01-28 23 views
6

Tôi có một lớp cơ sở thực hiện INotifyPropertyChanged:INotifyPropertyChanged và Threading

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

public event PropertyChangedEventHandler PropertyChanged; 

Tôi có một lớp có nguồn gốc với một tài sản Latitude như vậy:

private double latitude; 

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

lớp được thừa kế của tôi cũng có một phương pháp Fly rằng thao túng Latitude.

Tôi cũng có một mẫu với một TextBox ràng buộc để Latitude của lớp được thừa kế của tôi:

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

Một chủ đề được sử dụng để khởi Fly như vậy:

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

Khi Latitude thay đổi, một ngoại lệ được ném:

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

Trả lời

8

Điều này có vẻ là một vấn đề kỳ lạ với ái lực luồng. Cuối cùng, mã đang cố gắng cập nhật từ một chuỗi không phải UI - tôi không rõ tại sao nó không chỉ hiển thị ngoại lệ cross-thread, mặc dù - tôi tự hỏi liệu đây có phải là một trình xử lý ngoại lệ bắt tất cả hay không. Nếu tôi loại bỏ các BindingSource (và ràng buộc trực tiếp với đối tượng, đó là hợp lệ) bạn làm có được một ngoại lệ cross-thread (mà tôi mong đợi).

Cá nhân, tôi sẽ nghiêng để xử lý điều này bằng tay, ví dụ: đăng ký cho sự kiện này với một phương pháp mà không một Invoke đến thread UI và cập nhật Text bằng tay. Tuy nhiên, tôi chỉ kiểm tra nếu một số mã liên kết chéo ren trước có thể giúp ...


Dưới đây là một ví dụ sử dụng 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); 
      } 
     } 
    } 


} 

Dưới đây là một ví dụ sử dụng một (sửa đổi) phiên bản của một số mã luồng cũ của tôi:

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 đã thêm hai * khác nhau * ví dụ –

+0

@WulfgarPro - vâng, tôi chỉ đơn giản là ngắn gọn với ví dụ - giới hạn nó ở mức tối thiểu mà sẽ hiển thị * một cái gì đó * đang xảy ra. –

+0

@Marc Gravell - Tôi đã nhận được ví dụ Invoke thành công. Tôi sẽ thừa nhận tôi vẫn còn khá mới khi nói đến các đại biểu và xử lý sự kiện. Tôi đã thử một vài điều nhưng tôi tiếp tục đưa ra một 'Không thể truy cập một đối tượng được xử lý có tên là" FormName "' ngoại lệ khi cố gắng thoát khỏi ứng dụng của tôi. Bất kỳ ý tưởng? – wulfgarpro