选项卡控件 class 具有 2 个通用类型的选项卡和页面,它们彼此 link

Tab control class with 2 generic types for tab and page that link to each other

我正在尝试为 UI API 提供基础 class 以提供 Tab 控件。它在 C#.NET (4.5) 中,但未使用 WinForms。

我的选项卡控件工作得很好,但要求在外观和功能上都有各种自定义选项卡和页面,而不是为每个选项卡和页面克隆大量代码,我试图提供一个通用基础 class,你给 TTabTPage 类型。

想法在 API 然后我可以提供 classes,它只是将通用基础包装到非通用 class 中以实际使用:DefaultTabs : BaseTabs<DefaultTab, DefaultTabPage>

我没想到这会特别麻烦,但一路上我都弄糊涂了,我很确定我开始对这个问题视而不见了。

这是一个精简版:

namespace ExtendTabs.soExample
{
    using System.Collections.Generic;

    public class Example<TTab, TPage>
        where TTab : Tab<TPage>, new()
        where TPage : TabPage<TTab>, new()
    {
        private List<TTab> tabs;

        public Example()
        {
            this.tabs = new List<TTab>();

            this.tabs.Add(new TTab());
        }
    }

    public class Tab<TPage>
        where TPage : new()  //  where TPage : TabPage<..? All I can think of is "TabPage<Tab<TPage>>" and that seems very wrong.
    {
        public Tab()
        {
            this.Page = new TPage(); // Can't pass this in because of the where new() constraint.
            //this.Page.Tab = this;  // Can't do this because TPage does not contain where
            //this.Page.Link(this);  // Can't do this because TPage does not contain where
        }

        public TPage Page { get; private set; }
    }

    public class TabPage<TTab>
    {
        public TabPage() // Can't take in Tab<TPage> here because of type problems and new() constrain used.
        {
        }

        public TTab Tab { get; internal set; }

        internal void Link(TTab tab)
        {
            this.Tab = tab;
        }
    }
}

2个主要问题是:

我希望我已经关注这个问题太久了,并且试图让这个问题变得过于复杂。看起来它应该比这真的容易得多。有什么建议吗?


第一个问题源于主 class 不包括与子 class 相同的通用约束。根据 link Siva 提供的内容,我现在添加了 new() 约束并修复了该错误。

基于此SO Post,您可以将示例class更改为:

public class Example<TTab, TPage>  // 'TPage' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TPage' in the generic type or method 'ExtendTabs.soExample.Tab<TPage>'
        where TTab : Tab<TPage>, new() 
        where TPage : TabPage<TTab>, new() //new() is provided here as a means to indicate constraint

    {
        private List<TTab> tabs;

        public Example()
        {
            this.tabs = new List<TTab>();

            this.tabs.Add(new TTab());
        }
    }

我想我现在已经解决了这个问题:

namespace WindowsFormsApplication1.soExample
{
    using System.Collections.Generic;

    public abstract class BaseTabs<TTab, TPage>
        where TTab : BaseTabsTab<TTab, TPage>, new()
        where TPage : BaseTabsTabPage<TTab, TPage>, new()
    {
        private List<TTab> tabs;

        public BaseTabs()
        {
            this.tabs = new List<TTab>();
        }

        public IEnumerable<TPage> Pages
        {
            get
            {
                foreach (TTab tab in this.Tabs)
                {
                    yield return tab.Page;
                }
            }
        }

        public IEnumerable<TTab> Tabs { get { return this.tabs; } }

        public TTab Add()
        {
            TTab tab = new TTab();
            this.tabs.Add(tab);
            return tab;
        }
    }

    public abstract class BaseTabsTab<TTab, TPage>
        where TTab : BaseTabsTab<TTab, TPage>, new()
        where TPage : BaseTabsTabPage<TTab, TPage>, new()
    {
        public BaseTabsTab()
        {
            this.Page = new TPage();
            this.Page.Tab = (TTab)this;
        }

        public TPage Page { get; private set; }
    }

    public abstract class BaseTabsTabPage<TTab, TPage>
        where TTab : BaseTabsTab<TTab, TPage>, new()
        where TPage : BaseTabsTabPage<TTab, TPage>, new()
    {
        public BaseTabsTabPage()
        {
        }

        public TTab Tab { get; internal set; }
    }

    public class DefaultTab : BaseTabsTab<DefaultTab, DefaultTabPage> { }

    public class DefaultTabPage : BaseTabsTabPage<DefaultTab, DefaultTabPage> { }

    public class DefaultTabs : BaseTabs<DefaultTab, DefaultTabPage> { }
}

这为选项卡和页面提供了强类型支持,双向支持,并允许创建具有扩展选项卡或页面的新选项卡。 3 个默认值 类 允许您使用它而不会卷入您不需要的肮脏的泛型减速:

DefaultTabs tabs = new DefaultTabs();
tabs.Add();
foreach (DefaultTab tab in tabs.Tabs) { }
foreach (DefaultTabPage page in tabs.Pages) { }

现在也应该清楚 link 从选项卡或页面返回主选项卡容器。

只是想我会 post 解决方案,以防其他人遇到类似的鸡和蛋仿制药问题。