Подтвердить что ты не робот

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

Во-первых, это вопрос о настольном приложении с использованием Windows Forms, а не ASP.NET вопрос.

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

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

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

otherForm.nameOfControl.Visible = false;

Но лучший способ это сделать? Делает элементы управления public на другой форме, считающейся "лучшей практикой"? Есть ли "лучший" способ доступа к элементам управления в другой форме?

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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

Ответ 3

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

Чтобы сделать его общедоступным, также не самый лучший способ.

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

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; }
}

Ответ 4

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

Ответ 5

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

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

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

Form1 ob = new Form1();
ob.Visible = true;
this.Close();

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

Ответ 9

Вы можете

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

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

Ответ 10

С помощью свойства (выделено) я могу получить экземпляр класса 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; } }
    }
}

Ответ 11

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

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

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

Ответ 12

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

У вас есть мое сочувствие!;)


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

Ответ 13

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

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

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

Также будет намного проще записывать единичные и приемочные тесты, потому что вы можете следовать " Trust But Verify":

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

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

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

Ответ 14

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

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

Ответ 15

Шаг 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];
        }
    }
}

Ответ 16

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

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

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

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

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

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

Или же

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

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

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

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

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

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

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

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

2 - Любая форма, которая хочет открыть окончательную форму (в нашем примере это 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.


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

Ответ 17

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
*/