在程序制作过程中,UserControl需要放置到主窗体MainForm中,由于UserControl需要用到MainForm中的一些数据,所以建立了一个专门的Model类来保存这些数据:
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; }));
一切问题解决.