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

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

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

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

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

otherForm.nameOfControl.Visible = false;

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

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

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

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

12.08.2008 07:32:32
Вы получаете доступ к этим элементам управления извне из отдельного потока?
Tanerax 12.08.2008 14:50:43
Убедитесь, что вы поместили это в свой собственный класс, который принимает форму в конструкторе. Он должен реализовывать интерфейс IDisposable и иметь свойство утилизироваться после завершения. Также необходимо использовать отслеживание ссылок (увеличение / уменьшение целого числа, поэтому рекурсивный вызов его не вызовет проблем) и скрытие элементов управления только при переходе от 0 до 1. И только их повторное отображение при переходе от 1 до 0.
TamusJRoyce 3.10.2011 13:55:12
17 ОТВЕТОВ

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

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

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

20
6.08.2014 11:42:23
иногда связь в порядке ... программист должен быть в состоянии решить. Вот почему защищенный доступ - это глупо.
eat_a_lemon 26.07.2011 03:04:53

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

2
12.08.2008 08:13:21

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

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

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

37
22.12.2014 21:21:01

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

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

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

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; }
}
8
12.08.2008 07:42:57

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

5
23.05.2017 11:54:50

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

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

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

0
12.08.2008 08:12:50

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

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


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

0
12.08.2008 07:57:25

Я согласен с использованием событий для этого. Так как я подозреваю, что вы создаете 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;
}
1
7.02.2016 18:20:21

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

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

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

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

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

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

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

0
17.08.2008 01:23:36

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

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

0
7.09.2008 18:20:44

Вы можете

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

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

1
14.04.2009 10:06:36

С помощью свойства (выделено) я могу получить экземпляр класса 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; } }
    }
}
1
7.02.2016 18:19:37
  1. Используйте обработчик событий, чтобы уведомить другую форму, чтобы обработать его.
  2. Создайте открытое свойство в дочерней форме и получите доступ к нему из родительской формы (с действительным приведением).
  3. Создайте другой конструктор в дочерней форме для установки параметров инициализации формы
  4. Создание пользовательских событий и / или использование (статических) классов.

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

2
6.08.2014 12:03:47

Шаг 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];
        }
    }
}
0
7.02.2016 18:19:56

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

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

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

Form1 ob = new Form1();
ob.Visible = true;
this.Close();
3
7.09.2014 19:45:58

Изменить модификатор с публичного на внутренний. .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она открыта.


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

0
13.12.2018 21:59:03
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
*/
0
25.05.2017 18:47:00
Из очереди просмотра : Могу ли я попросить вас добавить контекст вокруг вашего исходного кода. Ответы только на код трудно понять. Это поможет вам и будущим читателям, если вы сможете добавить больше информации в свой пост.
RBT 25.05.2017 01:52:00