自定义MainTabControl设计器:如何为RaiseComponentChanged提供TabPageCollection旧值?
问题
我正在为自定义的MainTabControl(继承自TabControl)创建自定义设计器,在OnAddTab方法中通过添加新选项卡修改TabPageCollection。请问如何为RaiseComponentChanged方法提供正确的oldValue?TabPageCollection是引用类型,我了解深拷贝方案,但希望找到更优的解决办法。
代码示例
public class MainTabControlDesigner : ControlDesigner { DesignerVerbCollection _verbs; IDesignerHost _designerHost; //... public override DesignerVerbCollection Verbs { get { if(_verbs == null) { _verbs = new DesignerVerbCollection() { new DesignerVerb("Add Tab", new EventHandler(OnAddTab)), new DesignerVerb("Remove Tab", new EventHandler(OnRemoveTab)) }; MainTabControl mainTabControl = Control as MainTabControl; if (mainTabControl != null) { _verbs[1].Enabled = mainTabControl.TabPages.Count > 0; } } return _verbs; } } public void OnAddTab(object sender, EventArgs e) { MainTabControl parentControl = Control as MainTabControl; MainTabControl.TabPageCollection oldTabs = parentControl.TabPages; DesignerTransaction transaction = null; try { transaction = _designerHost.CreateTransaction("Add Tab"); RaiseComponentChanging(TypeDescriptor.GetProperties(parentControl)["TabPages"]); MainTabPage newPage = (MainTabPage)_designerHost.CreateComponent(typeof(MainTabPage)); newPage.Text = newPage.Name; parentControl.TabPages.Add(newPage); parentControl.SelectedTab = newPage; RaiseComponentChanged(TypeDescriptor.GetProperties(parentControl)["TabPages"], oldTabs, parentControl.TabPages); transaction.Commit(); } catch { MessageBox.Show("Exception occured during adding the tab"); transaction?.Cancel(); } } //... }
解决方案
不需要对TabPageCollection做深拷贝,只需要保存修改前集合中项的引用快照即可,具体做法如下:
- 保存修改前的选项卡引用数组:在调用
RaiseComponentChanging之前,将当前TabPages集合中的项转为数组,这个数组就是修改前的内容快照,无需拷贝TabPage对象本身(仅保存引用)。 - 正确调用
RaiseComponentChanged:将这个数组作为oldValue传入,newValue使用修改后的TabPageCollection即可。
修改后的OnAddTab方法代码:
public void OnAddTab(object sender, EventArgs e) { MainTabControl parentControl = Control as MainTabControl; if (parentControl == null) return; DesignerTransaction transaction = null; try { transaction = _designerHost.CreateTransaction("Add Tab"); // 保存修改前的选项卡引用快照 TabPage[] oldTabPages = parentControl.TabPages.Cast<TabPage>().ToArray(); PropertyDescriptor tabPagesProp = TypeDescriptor.GetProperties(parentControl)["TabPages"]; RaiseComponentChanging(tabPagesProp); MainTabPage newPage = (MainTabPage)_designerHost.CreateComponent(typeof(MainTabPage)); newPage.Text = newPage.Name; parentControl.TabPages.Add(newPage); parentControl.SelectedTab = newPage; // 传递快照作为oldValue,当前集合作为newValue RaiseComponentChanged(tabPagesProp, oldTabPages, parentControl.TabPages); // 更新移除按钮的启用状态 _verbs[1].Enabled = parentControl.TabPages.Count > 0; transaction.Commit(); } catch { MessageBox.Show("添加选项卡时发生异常"); transaction?.Cancel(); } }
方案说明
TabPageCollection是引用类型,修改前后集合本身的引用不变,直接传递原集合作为oldValue无法让设计器感知到内容变化。- 使用
ToArray()创建临时数组的开销极小,仅保存TabPage的引用,比深拷贝集合对象高效得多。 - 设计器只需要知道集合的内容发生了变更,而非集合对象被替换,因此传递旧内容的引用快照完全满足需求。
内容的提问来源于stack exchange,提问作者NeverDoomedEnough
相关产品推荐
相关产品推荐

