Лучший способ получить доступ к элементу управления в другой форме в Windows Forms?

c# winforms controls

168178 просмотра

17 ответа

950 Репутация автора

Прежде всего, это вопрос о настольном приложении, использующем Windows Forms, а не вопрос ASP.NET .

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

otherForm.Controls["nameOfControl"].Visible = false;

Это не работает так, как я ожидал. Я получаю исключение Main. Однако, если я сделаю элементы управления publicвместо этого private, я смогу получить к ним доступ напрямую, так что ...

otherForm.nameOfControl.Visible = false;

Но это лучший способ сделать это? publicСчитается ли создание элементов управления в другой форме «наилучшей практикой»? Есть ли "лучший" способ доступа к элементам управления в другой форме?

Дальнейшее объяснение:

Это на самом деле своего рода продолжение другого вопроса, который я задал: Лучший метод для создания интерфейса типа «диалог древовидных настроек» в C #? , Ответ, который я получил, был замечательным и решил многие, многие организационные проблемы, с которыми я столкнулся в плане обеспечения простоты и легкости работы с пользовательским интерфейсом как во время выполнения, так и во время проектирования. Тем не менее, это подняло эту единственную проблему - легко управлять другими аспектами интерфейса.

По сути, у меня есть корневая форма, которая создает множество других форм, которые находятся на панели в корневой форме. Так, например, переключателю в одной из этих подформ может потребоваться изменить состояние значка строки состояния в основной корневой форме. В этом случае мне нужна субформа для общения с элементом управления в строке состояния родительской (корневой) формы. (Надеюсь, это имеет смысл, а не в стиле «кто на первом»).

Автор: Dylan Bennett Источник Размещён: 12.08.2008 07:32

Ответы (17)


20 плюса

21535 Репутация автора

Лично я бы порекомендовал НЕ делать этого ... Если он реагирует на какое-то действие и ему нужно изменить внешний вид, я бы предпочел поднять событие и позволить ему разобраться ...

Такая связь между формами всегда заставляет меня нервничать. Я всегда стараюсь сделать интерфейс максимально легким и независимым .

Надеюсь, это поможет. Возможно, вы могли бы расширить сценарий, если нет?

Автор: Rob Cooper Размещён: 12.08.2008 07:35

2 плюса

105865 Репутация автора

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

Автор: Ed S. Размещён: 12.08.2008 07:40

37 плюса

82530 Репутация автора

Вместо того, чтобы сделать элемент управления общедоступным, вы можете создать свойство, которое контролирует его видимость:

public bool ControlIsVisible
{
     get { return control.Visible; }
     set { control.Visible = value; }
}

Это создает надлежащий метод доступа к этому элементу управления, который не предоставляет весь набор свойств элемента управления.

Автор: Jon Limjap Размещён: 12.08.2008 07:41

8 плюса

6009 Репутация автора

Первый не работает, конечно. Элементы управления в форме являются частными, видимыми только для этой формы по дизайну.

Делать все это публично - тоже не лучший способ.

Если я хотел бы раскрыть что-то для внешнего мира (что также может означать другую форму), я сделаю это достоянием общественности.

public Boolean nameOfControlVisible
{
    get { return this.nameOfControl.Visible; }
    set { this.nameOfControl.Visible = value; }
}

Вы можете использовать это открытое свойство, чтобы скрыть или показать элемент управления или задать текущее свойство видимости элемента управления:

otherForm.nameOfControlVisible = true;

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

public ControlType nameOfControlP
{
    get { return this.nameOfControl; }
    set { this.nameOfControl = value; }
}
Автор: Biri Размещён: 12.08.2008 07:42

5 плюса

6009 Репутация автора

После прочтения дополнительных деталей, я согласен с robcthegeek : поднять событие. Создайте собственный EventArgs и передайте через него необходимые параметры.

Автор: Biri Размещён: 12.08.2008 07:48

0 плюса

105865 Репутация автора

Ваши детские формы действительно должны быть формами? Могут ли они быть пользовательскими элементами управления? Таким образом, они могли бы легко вызывать события для основной формы, чтобы обрабатывать их, и вы могли бы лучше инкапсулировать их логику в один класс (по крайней мере, логически, они уже после всех классов).

@Lars: ты прямо здесь. Это было то, что я делал в мои первые дни, и с тех пор мне не приходилось это делать, поэтому я сначала предложил вызвать событие, но другой мой метод действительно нарушил бы любое подобие инкапсуляции.

@Rob: Да, звучит о праве :). 0/2 на этом ...

Автор: Ed S. Размещён: 12.08.2008 07:55

0 плюса

21535 Репутация автора

@Lars, хороший вызов для раздачи ссылок на Form, я тоже это видел. Насти. Никогда не видел, чтобы они передавали их в слой BLL! Это даже не имеет смысла! Это могло серьезно повлиять на производительность, верно? Если где-то в BLL ссылка будет сохранена, форма останется в памяти, верно?

Вы имеете мое сочувствие! ;)


@Ed, RE ваш комментарий о создании Forms UserControls. Дилан уже указал, что корневая форма создает множество дочерних форм, создавая впечатление приложения MDI (где я предполагаю, что пользователи могут захотеть закрыть различные формы). Если я прав в этом предположении, я думаю, что их лучше всего хранить в форме. Конечно, открыт для исправления, хотя :)

Автор: Rob Cooper Размещён: 12.08.2008 07:57

1 плюс

11069 Репутация автора

Я согласен с использованием событий для этого. Так как я подозреваю, что вы создаете MDI-приложение (поскольку вы создаете много дочерних форм) и динамически создаете окна и, возможно, не знаете, когда отписаться от событий, я бы порекомендовал вам взглянуть на шаблоны слабых событий . Увы, это доступно только для фреймворков 3.0 и 3.5, но что-то подобное можно реализовать довольно легко при наличии слабых ссылок.

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

public static Control FindControl(Form form, string name)
{
    foreach (Control control in form.Controls)
    {
        Control result = FindControl(form, control, name);

        if (result != null)
            return result;
    }

    return null;
}

private static Control FindControl(Form form, Control control, string name)
{
    if (control.Name == name) {
        return control;
    }

    foreach (Control subControl in control.Controls)
    {
        Control result = FindControl(form, subControl, name);

        if (result != null)
            return result;
    }

    return null;
}
Автор: Patrik Svensson Размещён: 12.08.2008 02:36

0 плюса

50520 Репутация автора

Вы должны когда-либо получать доступ только к содержимому одного представления из другого, если вы создаете более сложные элементы управления / модули / компоненты. В противном случае вы должны сделать это через стандартную архитектуру Model-View-Controller: вы должны подключить включенное состояние элементов управления, которые вас интересуют, к некоторому предикату уровня модели, который предоставляет правильную информацию.

Например, если бы я хотел включить кнопку «Сохранить» только тогда, когда была введена вся необходимая информация, у меня был бы метод предиката, который сообщает, когда объекты модели, представляющие эту форму, находятся в состоянии, которое можно сохранить. Затем в контексте, где я выбираю, активировать ли кнопку, я бы просто использовал результат этого метода.

Это приводит к гораздо более четкому отделению бизнес-логики от логики представления, позволяя им развиваться более независимо друг от друга - позволяя легко создать один внешний интерфейс с несколькими внутренними компонентами или несколько внешних интерфейсов с одним внутренним интерфейсом.

Кроме того, гораздо проще будет написать модульные и приемочные тесты, поскольку при этом можно следовать шаблону « доверяй, но проверяй »:

  1. Вы можете написать один набор тестов, которые настраивают объекты вашей модели различными способами, и проверить, что предикат «является пригодным для сохранения» возвращает соответствующий результат.

  2. Вы можете написать отдельный набор для этой проверки, правильно ли подключена кнопка «Сохранить» к предикату «можно сохранить» (что бы это ни было для вашей платформы, в Какао в Mac OS X это часто происходит через привязку).

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

Автор: Chris Hanson Размещён: 17.08.2008 01:23

0 плюса

2403 Репутация автора

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

В своем древовидном представлении вы внесете изменения в модель предпочтений, после чего будет запущено событие. В других формах вы будете подписываться на изменения, которые вас интересуют. В обработчике событий, который вы используете для подписки на изменения свойств, вы используете this.InvokeRequired, чтобы увидеть, находитесь ли вы в нужном потоке для создания пользовательского интерфейса. вызовите, если нет, то используйте this.BeginInvoke для вызова нужного метода для обновления формы.

Автор: Garo Yeriazarian Размещён: 07.09.2008 06:20

1 плюс

1224 Репутация автора

Ты можешь

  1. Создайте открытый метод с необходимым параметром в дочерней форме и вызовите его из родительской формы (с допустимым приведением)
  2. Создайте публичное свойство в дочерней форме и получите доступ к нему из родительской формы (с действительным приведением)
  3. Создайте другой конструктор в дочерней форме для установки параметров инициализации формы
  4. Создание пользовательских событий и / или использование (статических) классов

Лучшей практикой будет №4, если вы используете немодальные формы.

Автор: Davorin Размещён: 14.04.2009 10:06

1 плюс

11 Репутация автора

С помощью свойства (выделено) я могу получить экземпляр класса MainForm. Но это хорошая практика? Что вы порекомендуете?

Для этого я использую свойство MainFormInstance, которое выполняется в методе OnLoad.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LightInfocon.Data.LightBaseProvider;
using System.Configuration;

namespace SINJRectifier
{

    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            UserInterface userInterfaceObj = new UserInterface();
            this.chklbBasesList.Items.AddRange(userInterfaceObj.ExtentsList(this.chklbBasesList));
            MainFormInstance.MainFormInstanceSet = this; //Here I get the instance
        }

        private void btnBegin_Click(object sender, EventArgs e)
        {
            Maestro.ConductSymphony();
            ErrorHandling.SetExcecutionIsAllow();
        }
    }

    static class MainFormInstance  //Here I get the instance
    {
        private static MainForm mainFormInstance;

        public static MainForm MainFormInstanceSet { set { mainFormInstance = value; } }

        public static MainForm MainFormInstanceGet { get { return mainFormInstance; } }
    }
}
Автор: eduardolucioac Размещён: 13.05.2011 07:30

2 плюса

21 Репутация автора

  1. Используйте обработчик события, чтобы уведомить другую форму, чтобы обработать его.
  2. Создайте открытое свойство в дочерней форме и получите к нему доступ из родительской формы (с действительным приведением).
  3. Создайте другой конструктор в дочерней форме для установки параметров инициализации формы
  4. Создание пользовательских событий и / или использование (статических) классов.

Лучшей практикой будет №4, если вы используете немодальные формы.

Автор: user811204 Размещён: 22.06.2011 09:36

0 плюса

89 Репутация автора

Шаг 1:

string regno, exm, brd, cleg, strm, mrks, inyear;

protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
    string url;
    regno = GridView1.Rows[e.NewEditIndex].Cells[1].Text;
    exm = GridView1.Rows[e.NewEditIndex].Cells[2].Text;
    brd = GridView1.Rows[e.NewEditIndex].Cells[3].Text;
    cleg = GridView1.Rows[e.NewEditIndex].Cells[4].Text;
    strm = GridView1.Rows[e.NewEditIndex].Cells[5].Text;
    mrks = GridView1.Rows[e.NewEditIndex].Cells[6].Text;
    inyear = GridView1.Rows[e.NewEditIndex].Cells[7].Text;

    url = "academicinfo.aspx?regno=" + regno + ", " + exm + ", " + brd + ", " +
          cleg + ", " + strm + ", " + mrks + ", " + inyear;
    Response.Redirect(url);
}

Шаг 2:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        string prm_string = Convert.ToString(Request.QueryString["regno"]);

        if (prm_string != null)
        {
            string[] words = prm_string.Split(',');
            txt_regno.Text = words[0];
            txt_board.Text = words[2];
            txt_college.Text = words[3];
        }
    }
}
Автор: Santosh Lodhi Размещён: 29.06.2011 08:24

3 плюса

31 Репутация автора

Предположим, у вас есть две формы, и вы хотите скрыть свойство одной формы через другую:

form1 ob = new form1();
ob.Show(this);
this.Enabled= false;

и когда вы хотите вернуть фокус с form1 с помощью кнопки form2, тогда:

Form1 ob = new Form1();
ob.Visible = true;
this.Close();
Автор: KARAN Размещён: 31.01.2012 12:14

0 плюса

11 Репутация автора

Изменить модификатор с публичного на внутренний. .Net намеренно использует приватный модификатор вместо публичного, потому что предотвращает любой незаконный доступ к вашим методам / свойствам / элементам управления из вашего проекта. На самом деле, публичный модификатор может быть доступен везде, поэтому они действительно опасны. Любое тело из вашего проекта может получить доступ к вашим методам / свойствам. Но во внутреннем модификаторе ни одно тело (кроме вашего текущего проекта) не может получить доступ к вашим методам / свойствам.

Предположим, вы создаете проект, в котором есть несколько секретных полей. Так что если эти поля доступны из вашего проекта, это может быть опасно и противоречит вашим первоначальным идеям. В качестве хорошей рекомендации могу сказать, что всегда используйте внутренний модификатор вместо публичного.

Но какой-то странный!

Я должен сказать также в VB.Net, хотя наши методы / свойства все еще являются частными, он может быть доступен из других форм / классов, вызывая форму как переменную без каких-либо проблем.

Я не знаю, почему в этом языке программирования поведение отличается от C #. Как мы знаем, оба используют одну и ту же платформу и утверждают, что они почти одинаковые серверные платформы, но, как вы видите, они по-прежнему ведут себя по-разному.

Но я решил эту проблему двумя способами. Или; используя интерфейс (который, как вы знаете, не рекомендуется, для интерфейсов обычно требуется общедоступный модификатор, а использование общедоступного модификатора не рекомендуется (как я уже говорил выше)),

Или же

Объявите всю форму в статическом классе и статической переменной, и все еще есть внутренний модификатор. Затем, когда вы предполагаете использовать эту форму для показа пользователям, передайте новую Form()конструкцию этому статическому классу / переменной. Теперь он может быть доступен везде, где вы хотите. Но вам все еще нужно что-то еще. Вы также объявляете свой внутренний модификатор элемента в Designer File of Form. Пока ваша форма открыта, она может быть доступна везде. Это может работать для вас очень хорошо.

Рассмотрим этот пример.

Предположим, вы хотите получить доступ к TextBox формы.

Таким образом, первая задача - объявление статической переменной в статическом классе (причина статичности - в простоте доступа без использования новых клавиш в будущем).

Затем перейдите к классу дизайнеров той формы, которая предполагает доступ к другим формам. Измените объявление модификатора TextBox с частного на внутреннее. Не волнуйся; .Net никогда не изменяет его снова на приватный модификатор после вашего изменения.

В-третьих, когда вы хотите вызвать эту форму для открытия, передайте новую конструкцию формы этой статической переменной - >> статический класс.

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

Посмотрите на код ниже (у нас есть три объекта. 1 - статический класс (в нашем примере мы называем его A)

2 - Любая форма, которая хочет открыть окончательную форму (в нашем примере это TextBox FormB).

3 - Реальная форма, которую нам нужно открыть, и мы предполагаем доступ к ее внутренней TextBox1(в нашем примере FormC).

Посмотрите на коды ниже:

internal static class A
{
    internal static FormC FrmC;
}

FormB ...
{
    '(...)
    A.FrmC = new FormC();
    '(...)
}

FormC (Designer File) . . . 
{
     internal System.Windows.Forms.TextBox TextBox1;
}

Вы можете получить доступ к этой статической переменной (здесь FormC) и ее внутреннему контролю (здесь Textbox1) где угодно и когда угодно, пока FormCона открыта.


Любой комментарий / идея, дайте мне знать. Я рад услышать от вас или кого-либо еще об этой теме больше. Честно говоря, у меня были некоторые проблемы, связанные с этой проблемой в прошлом. Наилучшим способом было второе решение, которое, я надеюсь, сработает для вас. Дайте мне знать любую новую идею / предложение.

Автор: Mansoor Bozorgmehr Размещён: 16.08.2016 10:12

0 плюса

21 Репутация автора

public void Enable_Usercontrol1()
{
    UserControl1 usercontrol1 = new UserControl1();
    usercontrol1.Enabled = true;
} 
/*
    Put this Anywhere in your Form and Call it by Enable_Usercontrol1();
    Also, Make sure the Usercontrol1 Modifiers is Set to Protected Internal
*/
Автор: user7993881 Размещён: 24.05.2017 08:29
Вопросы из категории :
32x32