在程序制作过程中,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; }));
一切问题解决.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2010-11-02 .NET开发不可错过的25款必备工具