簡體   English   中英

INotifyPropertyChanged和線程

[英]INotifyPropertyChanged and Threading

我有一個實現INotifyPropertyChanged的基類:

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

我還有一個Form,其TextBox綁定到我的派生類的Latitude

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.

這似乎是線程親和力的一個奇怪問題。 最終,代碼試圖從非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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM