C#创建嵌套控件的多个实例

C# create multiple instances of nested controls

我有一个选项卡式界面 - 其中选项卡将包含多个嵌套控件。特别是包含面板的 Panels、包含 Grids 等。甚至在某些情况下还包含额外的 Tab 控件。 (是的,它可能有点乱)

但是,现在我需要在 运行 时动态创建其中一些选项卡 - 并且仍然引用它们上的控件。所以 - 例如,假设我有类似

的东西

选项卡

小组

TabControl

选项卡

网格

Graph/Chart

小组

按钮

我需要为我需要显示的每个结果数据表创建多个新选项卡(我不知道我必须创建多少,直到 运行 时间 - 或者我会在设计时做这一切) .

我知道我将在 运行 时间创建这些控件 - 我可以轻松地为一个额外的实例创建 - 但随后我开始 运行 命名问题。我无法将三个 GridControl(都称为 DataGrid)添加到同一个表单中 - 因为 C# 是强类型的,所以我无法在 运行 时创建变量名。并且有时我还需要能够引用这些控件。

所以 - 我正在寻找可能的解决方案。我可以为我希望创建的每种类型的控件创建数组。每个选项卡有超过 15 个控件(有些是嵌套的)——因此它可能会变得有点混乱。但它将允许我访问每个控件——因为我可以使用选项卡页面的标签 属性 来允许我访问各种数组。如果我创建的数组最多可容纳 50 个元素 - 它应该绰绰有余(我没有看到用户创建超过 5 个或 10 个这些额外选项卡)。

因为我对 C# 和 Visual Studio 有点陌生 - 我想知道其他人会如何处理这类任务?您将如何在表单上创建多个嵌入式(嵌套)控件实例 - 知道您必须在代码的其他地方引用它们?

任何想法和指示将不胜感激。

谢谢

布拉德利

由于有任意数量的选项卡,您需要以编程方式管理它们。

So - I looking for possible solutions. I could create arrays for each type of control I am hoping to create. There are over 15 controls (some nested) for each tab - so it could get a little messy. But it would allow me to access each control - as I could use the Tag Property of the Tab page to allow me to access the various arrays. If I created the arrays to hold a max of 50 elements - it should be more than enough (I do not see users creating more then 5 or 10 of these extra tabs).

那确实会变得凌乱,并且容易出现错误。 Tag 在适当的情况下是非常有用的 属性,但通常你应该避免使用它,除非你有充分的理由。您可能会无意中引入会泄漏内存的循环引用。我发现它最适合存储相关的元数据,例如 ID(但是,避免在其中存储值类型,因为它们会变成 boxed)。

如果您还没有这样做,我建议您对在设计器中设置的名称采用与变量相同的命名约定。由于支持变量反映了这些名称,它应该可以帮助您避免名称与属性发生冲突,并使您的代码更加一致。我和我的团队使用约定 mSomeField 来表示私有字段和设计器集名称,多年来,它在避免大多数名称冲突方面为我们提供了很好的帮助。

首先设计一个新的UserControl,作为最常见的标签类别的内容,添加尽可能多的常见布局。为每个额外的选项卡类别设计额外的 UserControl。为您需要公开的每个嵌套控件添加访问器。

请注意,以下代码使用了一些 C#6/7 功能。

在实践中,它可能是这样的:

// Code-behind for the UserControl representing the content of the 1st tab category.
class Cat1TabContent : UserControl
{
    //...
    // These all refer to controls created and named from the designer.
    public Panel PrimaryPanel => primaryPanel;
    public TabControl TabManager => tabManager;
    public Panel SecondaryPanel => secondaryPanel;
    //...
}

管理选项卡(在主窗体和所有其他具有 TabControl 的控件中):

//...
private List<UserControl> tabContents = new List<UserControl>();

void AddTab<T>() where T : UserControl, new()
{
    var tab = new TabPage();
    var tabContent = new T();
    tabContents.Add(tabContent);
    tab.Controls.Add(tabContent);
    tabControl.Controls.Add(tab);
}

void RemoveTab(TabPage tab)
{
    if (tab == null) throw new ArgumentNullException(nameof(tab));

    if (tab.Controls.Count != 0 && tab.Controls[0] is UserControl tabContent) {
        tabContents.Remove(tabContent);
    }
    tabControl.Controls.Remove(tab);
}
//...

访问嵌套控件:

// Form >> Tab Control >> 1st Tab >> 1st Child.
// This assumes AddTab<Cat1Content>() was called.
var firstContent = (Cat1Content)tabContents[0];

// Content >> PrimaryPanel; Enumerates over nested controls.
foreach (var child in firstContent.PrimaryPanel.Controls) {
    // ...
}

// Content >> Tab Control; Enumerates over nested tabs. 
foreach (var child in firstContent.TabManager.Controls) {
    // This is safe, TabControl throws an exception if you try to add anything that isn't a TabPage.
    var tab = (TabPage)child;
    // ...
}