You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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做深拷贝,只需要保存修改前集合中项的引用快照即可,具体做法如下:

  1. 保存修改前的选项卡引用数组:在调用RaiseComponentChanging之前,将当前TabPages集合中的项转为数组,这个数组就是修改前的内容快照,无需拷贝TabPage对象本身(仅保存引用)。
  2. 正确调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:22:45