.NET 4.8 WinForms MDI子窗体脱离父级后CurrencyManager的PositionChanged事件失效
问题根本原因
当MDI子窗体的MdiParent属性被设置为null时,WinForms底层会销毁子窗体原有的句柄,重新创建一个顶层窗口的新句柄。此时窗体的默认BindingContext实例会被销毁重建,你在窗体加载时缓存的CurrencyManager已经是被废弃的旧实例,其绑定的事件自然不会再触发。
可行的解决方法
方案1:监听窗体HandleCreated事件重新绑定
每次窗体句柄重建时,重新获取CurrencyManager并绑定事件,同时记得解绑旧实例的事件避免内存泄漏。修改后的Form2代码如下:
public partial class Form2 : Form { DataTable dt; CurrencyManager cm; private void Form2_Load(object sender, EventArgs e) { prepareTable(); fillTable(); // 注册句柄创建事件 this.HandleCreated += Form2_HandleCreated; BindCmEvent(); } private void Form2_HandleCreated(object sender, EventArgs e) { // 句柄重建后重新绑定CurrencyManager事件 BindCmEvent(); } private void BindCmEvent() { // 先解绑旧实例的事件 if (cm != null) { cm.PositionChanged -= cm_PositionChanged; } // 重新从当前BindingContext获取最新的CurrencyManager cm = (CurrencyManager)this.BindingContext[dt]; cm.PositionChanged += cm_PositionChanged; // 同步当前位置显示 lblPos.Text = cm.Position.ToString(); } private void cm_PositionChanged(object sender, EventArgs e) { lblPos.Text = cm.Position.ToString(); } private void prepareTable() { dt = new DataTable(); dt.Columns.Add("Index", typeof(int)); dgv.DataSource = dt; } private void fillTable() { for (int i = 0; i < 100; i++) { dt.Rows.Add(i); } } }
方案2:使用独立的BindingContext
直接为窗体创建专属的BindingContext实例,不使用系统默认的实例,就不会受窗体句柄重建影响。改动量极小,推荐优先使用该方案:
// 仅需修改prepareTable方法即可 private void prepareTable() { dt = new DataTable(); dt.Columns.Add("Index", typeof(int)); // 单独创建BindingContext,不和窗体默认实例绑定,不会随句柄重建重置 this.BindingContext = new BindingContext(); cm = (CurrencyManager)this.BindingContext[dt]; cm.PositionChanged += new EventHandler(cm_PositionChanged); dgv.DataSource = dt; }
内容的提问来源于stack exchange,提问作者Wombat
相关产品推荐
相关产品推荐

