WinForms自定义UserControl集合属性编辑后设计器UI不更新求助
WinForms自定义控件:集合编辑后设计器即时刷新UI方案
问题场景
我正在开发名为SidebarControl的WinForms自定义UserControl,它包含List<SidebarMenuItem>类型的MenuItems属性,通过自定义SidebarMenuItemCollectionEditor在Visual Studio设计器中编辑。
属性定义:
[Editor(typeof(SidebarMenuItemCollectionEditor), typeof(UITypeEditor))] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public List<SidebarMenuItem> MenuItems { get; set; }
在集合编辑器中重写SetItems方法,尝试修改集合后重建菜单UI:
protected override object SetItems(object editValue, object[] value) { var updated = base.SetItems(editValue, value); if (Context?.Instance is SidebarControl sidebar) { sidebar.RebuildMenuFromItems(); // 基于MenuItems向面板添加按钮 } return updated; } // SidebarControl中的UI重建方法 public void RebuildMenuFromItems() { if (pnlMenubar == null) return; pnlMenubar.Controls.Clear(); foreach (var item in MenuItems) { AddMenuItemControl(item); } this.Refresh(); this.Invalidate(); }
当前问题:修改集合后,必须关闭并重新打开主窗体才能看到UI变化,需要实现设计器中即时刷新。
解决方案
1. 通知设计器属性已变更
在SidebarControl的RebuildMenuFromItems方法末尾添加设计模式下的变更通知,通过IDesignerHost告知设计器MenuItems属性已修改:
public void RebuildMenuFromItems() { if (pnlMenubar == null) return; pnlMenubar.Controls.Clear(); foreach (var item in MenuItems) { AddMenuItemControl(item); } this.Refresh(); this.Invalidate(); // 设计模式下触发属性变更通知 if (DesignMode) { var designerHost = (IDesignerHost)GetService(typeof(IDesignerHost)); if (designerHost != null) { var menuItemsProp = TypeDescriptor.GetProperties(this)["MenuItems"]; designerHost.RaiseComponentChanged(this, menuItemsProp, null, MenuItems); } } }
2. 在集合编辑器中触发组件变更通知
在SetItems方法中,通过IComponentChangeService直接通知设计器组件已发生变化:
protected override object SetItems(object editValue, object[] value) { var updated = base.SetItems(editValue, value); if (Context?.Instance is SidebarControl sidebar) { sidebar.RebuildMenuFromItems(); // 通知设计器控件已修改 if (Context is ITypeDescriptorContext typeContext) { var changeService = (IComponentChangeService)typeContext.GetService(typeof(IComponentChangeService)); changeService?.OnComponentChanged(sidebar, null, null, null); } } return updated; }
3. 优化设计模式下的重绘逻辑
在RebuildMenuFromItems中增强重绘操作,确保控件和子容器都能即时更新:
public void RebuildMenuFromItems() { if (pnlMenubar == null) return; pnlMenubar.SuspendLayout(); pnlMenubar.Controls.Clear(); foreach (var item in MenuItems) { AddMenuItemControl(item); } pnlMenubar.ResumeLayout(); pnlMenubar.PerformLayout(); this.Invalidate(); this.Update(); if (DesignMode) { this.PerformLayout(); // 若父容器存在也可触发刷新 Parent?.Invalidate(); } }
4. 改用BindingList实现自动变更通知(推荐)
将List<SidebarMenuItem>替换为BindingList<SidebarMenuItem>,它内置集合变更事件,设计器能自动感知集合的增删改操作,无需手动触发通知:
[Editor(typeof(SidebarMenuItemCollectionEditor), typeof(UITypeEditor))] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public BindingList<SidebarMenuItem> MenuItems { get; set; } = new BindingList<SidebarMenuItem>();
结合RebuildMenuFromItems方法,集合修改后UI会即时在设计器中更新。
内容的提问来源于stack exchange,提问作者Dino Thunder
相关产品推荐
相关产品推荐

