zoukankan      html  css  js  c++  java
  • 由INotifyPropertyChanged,BindingList绑定引发的跨线程异常及其解决办法

    在程序制作过程中,UserControl需要放置到主窗体MainForm中,由于UserControl需要用到MainForm中的一些数据,所以建立了一个专门的Model类来保存这些数据:

    View Code
    public class DealReleaseModel:INotifyPropertyChanged
       {
            private long dealId;
            public long DealId
            {
                get { return dealId; }
                set
                {
                    if (dealId != value)
                    {
                        dealId = value;
                        NotifyPropertyChanged("DealId");
                    }
                }
            }
    
            private int majorVersion;
            public int MajorVersion
            {
                get { return majorVersion; }
                set { majorVersion = value; NotifyPropertyChanged("MajorVersion"); }
            }
    
    
            private int privateVersion;
            public int PrivateVersion
            {
                get { return privateVersion; }
                set { privateVersion = value; NotifyPropertyChanged("PrivateVersion"); }
            }
    
            private int newState;
            public int NewState
            {
                get { return newState; }
                set { newState = value; NotifyPropertyChanged("NewState"); }
            }
    
            private string newStateStr;
            public string NewStateStr
            {
                get { return newStateStr; }
                set { newStateStr = value; NotifyPropertyChanged("NewStateStr"); }
            }
    
            private string dealVersionHandle;
            public string DealVersionHandle
            {
                get { return dealVersionHandle; }
                set { dealVersionHandle = value; NotifyPropertyChanged("DealVersionHandle"); }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void NotifyPropertyChanged(String info)
            {
                    PropertyChangedEventHandler property_changed = PropertyChanged;
                    if (property_changed != null)
                    {
                        property_changed(this, new PropertyChangedEventArgs(info));
                    }
            }
    }

    这个类是通过INotifyPropertyChanged进行监视的,一旦有值发生改变,便会马上抛出通知来.

    然后在UserControl中,将这个Model中的一些字段通过DataBindings给绑定起来,由于更新过程中,有跨线程操作,所以通过Control.Invoke进行调用:

    public void Bind()
    {
            txtDaemonDealId.Invoke((Action)(() =>
            {
                txtDaemonDealId.DataBindings.Add("Text", DataCache.dealReleaseModel, "DealId");
            }));
    }

    通过DataBindings将Model的DealId字段绑定到了TextBox上.

    然后我又新建了一个DataCache静态类,以便保存Model中的值.

    public static DealReleaseModel dealReleaseModel = new DealReleaseModel();

    这一切都完成后,我在MainForm主窗体中开始操纵这个静态类:

    public void SubscribeNotification(IntPtr dealInfo)
    {
                //some code here
                DataCache.dealReleaseModel.DealId = info.dealId;
                DataCache.dealReleaseModel.MajorVersion = info.majorVersion;
                DataCache.dealReleaseModel.PrivateVersion = info.privateVersion;
                DataCache.dealReleaseModel.NewState = info.newState;
                DataCache.dealReleaseModel.NewStateStr = info.newStateStr;
                DataCache.dealReleaseModel.DealVersionHandle = info.dealVersionHandle;
                //some code here
    }

    这个SubscribeNotification是通过委托来创建的,主要用于回调,所以运行在了一个异步线程上.这样之后,程序编译通过,运行.第一次运行正常,但是一旦这个Model中有对象被改变的时候就会抛出:

    Cross-thread operation not valid: Control 'txtDaemonDealId' accessed from a thread other than the thread it was created on.

    我用异步操作txtDaemonDealId了呀,为什么还会出现问题了?

    原因呢?

    其实, SubscribeNotification本身处于一个线程中,而txtDaemonDealId绑定肯定处于另一个线程(UI线程)中,如果两个处理均在同一个线程中进行,肯定会发生阻塞,导致界面假死。如果从一个直接访问另外一个,肯定是要出现问题的(由于采用了INotifyPropertyChanged接口,所以Model的任何改变都会自动更新到前台UI上),所以在这里,我们要以异步方式来更新Model,让其数据的更新可以和UI进行交互.

    修改为:

     this.Invoke((Action)(() =>
          {
                    DataCache.dealReleaseModel.DealId = info.dealId;
                     DataCache.dealReleaseModel.MajorVersion = info.majorVersion;
                    DataCache.dealReleaseModel.PrivateVersion = info.privateVersion;
                    DataCache.dealReleaseModel.NewState = info.newState;
                    DataCache.dealReleaseModel.NewStateStr = info.newStateStr;
                    DataCache.dealReleaseModel.DealVersionHandle = info.dealVersionHandle;
                }));

    一切问题解决.

  • 相关阅读:
    谈谈图片上传及canvas压缩的流程
    前端应该懂得初级Web分析指标
    java OPENCV 连通域, Imgproc.findContours 例子,参数说明
    [学习opencv]高斯、中值、均值、双边滤波
    Opencv 图像叠加 添加水印
    帧间提取水印
    opencv mat 转灰度图
    编写一条sql命令,sql删除没有中文的表
    使用JavaCV/OpenCV抓取并存储摄像头图像
    周掌柜
  • 原文地址:https://www.cnblogs.com/scy251147/p/2751640.html
Copyright © 2011-2022 走看看