C#-动态创建控件并访问它们

本文关键字:访问 控件 动态 创建 C#- | 更新日期: 2023-09-27 18:29:54

我正在创建一个带有选项卡功能的简单记事本类型的应用程序。我正在运行时创建TabControl、它的TabPages和RichTextBoxes。我在类范围内实例化了它们。还有一个名为"新建"的MenuStrip项目,通过单击可以添加更多选项卡页面。

TabControl tbcEditor = new TabControl();
TabPage tbPage = new TabPage();
RichTextBox rtb = new RichTextBox();
private void frmTextEditor_Load(object sender, EventArgs e)
{
     Controls.Add(tbcEditor);
     tbcEditor.Dock = DockStyle.Fill;
     tbcEditor.TabPages.Add(tbPage);
     tbPage.Controls.Add(rtb);
     rtb.Dock = DockStyle.Fill;
}
private void newToolStripMenuItem_Click(object sender, EventArgs e)
{
     //TabPage tbPage = new TabPage();
     //RichTextBox rtb = new RichTextBox();
     tbPage.Controls.Add(rtb);
     rtb.Dock = DockStyle.Fill;
     tbcEditor.TabPages.Add(tbPage);
}

我面临的问题有点难以解释。我会尽力的。加载表单时,一切都按预期进行。TabControl使用添加了RichTextBox的TabPage创建。然而,如果我点击"新建"按钮添加另一个页面,它就会发疯。创建了一个新的TabPage,但没有添加RichTextBox。也没有抛出任何错误。如果我取消注释掉这两行(在MenuItem单击事件下),这两行创建了TabPage和RichTextBox的两个实例,那么一切都可以按照我的意愿进行。

现在我的第一个问题是,为什么我必须再次只创建这两种类型(TabPage、RichTextBox)的新实例,而不创建TabControl?正如您在最后一行中看到的,我可以再次使用tbcEditor。而不是CCD_ 2和CCD_。

当然,我可以在本地范围内再次声明它们,但随后出现了另一个问题。如果我想说,添加复制、粘贴功能,我应该这样做,对吧?

Clipboard.SetDataObject(rtb.SelectedText);

但是我不能访问rtb,因为它被声明为本地的。

我对此感到非常困惑,所以任何关于如何克服这两个问题的建议和想法都将不胜感激。

谢谢。

C#-动态创建控件并访问它们

If I un-comment out those 2 lines(under MenuItem click event), which creates 2 instances of TabPage and RichTextBox, everything works as I want.

当您取消注释这些行时,您将再次向容器面板中添加同一个富文本框和选项卡页面实例,这毫无意义。相反,在每个选项卡页面上添加新控件。(我希望这是要求)

Now my first question is why do I have to make new instances of only those 2 types(TabPage, RichTextBox) again but not TabControl?

TabControl是将TabPages作为子控件的父控件。一个TabControl下可以有多个选项卡。因此,除了已经添加的tbcEditor之外,您不需要创建TabControls。我们不会多次添加容器控件(除非有要求)。我们需要更多的表格吗?不,只有一个表单可以正确地保存所有子控件。类似地,只有一个TabControl可以容纳TabPages的集合。只有当你想要每个新选项卡的子选项卡时,你才会需要更多的TabControls,我想这不是要求。。

But I can't access rtb since it is declared as local.

这没什么大不了的。你可以用两种方法:

1) 通过循环搜索合适的控件。SelectedTab属性提供您想要的内容。

 private void someEvent(object sender, EventArgs e)
 {           
        foreach (Control c in tbcEditor.SelectedTab.Controls)
        {
            if (c is RichTextBox)
            {
                Clipboard.SetDataObject(((RichTextBox)c).SelectedText);
                break; //assuming u have just one main rtb there
            }
        }
 }

2) 在创建每个rtb时,将其标记到tabPage,然后可以获得所选选项卡页面的标记元素以获得富文本框。我会采用这种方法。

编辑:(一般情况下,请对您的代码进行以下更改):

 TabControl tbcEditor = new TabControl();
 private void frmTextEditor_Load(object sender, EventArgs e)
 {
      Controls.Add(tbcEditor);
      tbcEditor.Dock = DockStyle.Fill;
      AddMyControlsOnNewTab();
 }
private void AddMyControlsOnNewTab()
{
    TabPage tbPage = new TabPage();
    RichTextBox rtb = new RichTextBox();
    tbPage.Tag = rtb; //just one extra bit of line.
    tbcEditor.TabPages.Add(tbPage);
    tbPage.Controls.Add(rtb);
    rtb.Dock = DockStyle.Fill;
}
private void newToolStripMenuItem_Click(object sender, EventArgs e)
{
    AddMyControlsOnNewTab();
}

现在,你可以这样称呼它:

 private void someEvent(object sender, EventArgs e)
 {           
        RichTextBox rtb= (RichTextBox)tbcEditor.SelectedTab.Tag;
        Clipboard.SetDataObject(rtb.SelectedText);
        //or even better in just a line,
        //Clipboard.SetDataObject(((RichTextBox)tbcEditor.SelectedTab.Tag).SelectedText);
 }

在这里,你必须考虑的是,哪一个是你首先获得的控制权,哪一种是你没有得到的控制权。无论如何,你会得到TabPage,但不会得到RichTextBox。因此,您必须将RichTextBox标记为TabPage。由于Tag是object类型,所以必须强制转换它,因此必须指定它是哪种类型的对象。最后,这种方法的优点是不需要循环遍历列表,因此它的性能更高。并且你可以在TabPage中有更多的RichTextBox(前提是你只想从一组RichTextBox中复制文本,每个TabPage中一个)。。

注释行正在做它们应该做的事情。代码不将Richtextbox与Tabpage关联。

TabPage tbPage = new TabPage(); // Creates a new tabpage
RichTextBox rtb = new RichTextBox(); // Creates a new RichtextBox control.

TabControl是一个容器,所以一个实例就可以了。

另请参阅-http://sujay-ghosh.blogspot.in/2009/03/addingremoving-dynamically-created.html,与tabcontrols无关,而是如何动态创建控件。

希望这能有所帮助。

代码

tbPage.Controls.Add(rtb); 
rtb.Dock = DockStyle.Fill; 
tbcEditor.TabPages.Add(tbPage); 

获取现有文本框,将其添加到现有选项卡页面,然后将现有选项卡页面添加到编辑器中。既然已经这样做了,什么也没发生。

当您添加这两行时,您将创建文本框的新实例和一个新的选项卡页,这正是您想要的。后一个问题出现了,因为新声明的变量rtb隐藏了类中声明的变量——在另一种方法中,您只能访问类中声明(除非从选项卡中获得控制)的onde

为了避免无法访问正确的文本框,您可以将它们保存在列表(*)(或其他集合)中,并引用与当前活动选项卡关联的文本框。为此,您必须创建一个事件侦听器来查看当前激活了哪个选项卡。

(*)而不是只有一个

好吧,您需要在此处创建RichTextBox的新实例,而不是尝试向每个选项卡添加相同的实例。

 TabControl tbcEditor = new TabControl();
 //Get rid off this line --- TabPage tbPage = new TabPage();
 //Get rid off this line --- RichTextBox rtb = new RichTextBox();
 List<TabPage> _tabs = new  List<TabPage>();
 List<RichTextBox> _tbx = new  List<RichTextBox>();
 private void frmTextEditor_Load(object sender, EventArgs e) 
 {
      Controls.Add(tbcEditor);
      tbcEditor.Dock = DockStyle.Fill;
       AddNewTab();
 }
 private void newToolStripMenuItem_Click(object sender, EventArgs e) 
 {   
       AddNewTab();
 } 
 private void AddNewTab()
 {
    //TabPage 
        var tbPage = new TabPage();
        _tabs.Add(tbPage);
        //RichTextBox 
        var rtb = new RichTextBox();
        _tbx.Add(rtb);
        tbPage.Controls.Add(rtb);
        rtb.Dock = DockStyle.Fill;
        tbcEditor.TabPages.Add(tbPage); 
 }

这只需将选项卡和rtb添加到可以通过索引访问的集合中(也可以使用Dictionary进行命名访问等)。当然,还有其他方法,包括命名组件并在需要时循环使用。