C # - Создание элементов управления динамически и доступ к ним - PullRequest
1 голос
/ 03 апреля 2012

Я создаю простое приложение типа блокнота с функциональностью вкладок.Я создаю TabControl, его TabPages и RichTextBoxes во время выполнения.Я создал их на уровне класса.И есть пункт MenuStrip, который называется New, нажав на него, чтобы добавить больше вкладок.

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 создается с TabPage с добавленным RichTextBox.Однако, если я нажму эту кнопку «Новый», чтобы добавить другую страницу, то это сойдет с ума.Будет создан новый TabPage, но без добавления RichTextBox.Ошибок тоже не выдается.Если я откомментирую эти 2 строки (в событии щелчка MenuItem), который создает 2 экземпляра TabPage и RichTextBox, все работает так, как я хочу.

Теперь мой первый вопрос: почему я должен снова создавать новые экземпляры только этих 2 типов (TabPage, RichTextBox), а не TabControl?Как вы можете видеть в последней строке, я могу использовать tbcEditor еще раз.Но не tbPage и rtb.

Конечно, я могу снова объявить их в местном масштабе, но тогда возникает другая проблема.Если я хочу сказать, добавить функцию копирования, вставки, я должен сделать что-то вроде этого, верно?

Clipboard.SetDataObject(rtb.SelectedText);

Но я не могу получить доступ к rtb, поскольку он объявлен как локальный.

Я очень озадачен этим, поэтому любые предложения, идеи о том, как преодолеть эти 2 проблемы, будут высоко оценены.

Спасибо.

Ответы [ 4 ]

2 голосов
/ 03 апреля 2012

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.

Когда вы раскомментируете эти строки, вы снова добавляете тот же экземпляр расширенного текстового поля и вкладки на панель контейнера, что не имеет смысла.Вместо этого добавьте новые элементы управления foreach tabpage.(Надеюсь, это требование)

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.Поэтому вам не нужно создавать TabControls, кроме tbcEditor, который вы уже добавили.Мы не добавляем элементы управления контейнером более одного раза (если это не требуется).Нужно ли нам больше форм?Нет, только одна форма, которая может содержать все дочерние элементы управления правильно.Точно так же только один 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 имеет тип объекта, поэтому вы должны указать, какой это тип объекта.Наконец, этот метод имеет то преимущество, что вам не нужно перебирать список, поэтому он более производительный.И что у вас может быть больше RichTextBoxes в TabPage (при условии, что вы хотите скопировать текст только из одного набора RichTextBoxes, по одному из каждой TabPage) ..

0 голосов
/ 03 апреля 2012

Код

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

Принимает существующее текстовое поле, добавляет его на вкладку существующей вкладки, а затем добавляет эту существующую вкладку в редактор.Поскольку это уже сделано, ничего не происходит.

Когда вы добавляете эти две строки, вы создаете новые экземпляры текстового поля и новую вкладку, что именно то, что вы хотите.Последняя проблема возникает из-за того, что объявленная переменная rtb скрывает объявленную в классе - в другом методе вы можете получить доступ только к объявленному в классе onde (исключая возможность получения элемента управления из вкладки)

Чтобы обойтись без возможности доступа к нужному текстовому полю, вы можете сохранить их в списке (*) (или некоторой другой коллекции) и обратиться к списку, связанному с активной в данный момент вкладкой.Для этого вам нужно создать прослушиватель событий, чтобы увидеть, какая вкладка активирована правильно.

(*), а не один

0 голосов
/ 03 апреля 2012

Хорошо, вам нужно создать новые экземпляры 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 в коллекцию, к которой можно получить доступ по индексу (также можно использовать Словарь для именованного доступа и т. Д.). Конечно, есть и другие способы, в том числе просто называть компоненты и проходить по ним по мере необходимости и т. Д.

0 голосов
/ 03 апреля 2012

Комментированные строки делают именно то, что они должны делать.Код не связывает 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 / добавлениеremoving-динамически-созданный.html , не имеет ничего общего с tabcontrols, но как создавать элементы управления на лету.

Надеюсь, это поможет.

...