2008-08-12 2 views
45

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

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

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

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

otherForm.nameOfControl.Visible = false; 

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

Далее Пояснение:

Это на самом деле своего рода наблюдения на другой вопрос, я спросил, Best method for creating a “tree-view preferences dialog” type of interface in C#?. Ответ, который я получил, был большим и решал многие, многие организационные проблемы, которые я испытывал с точки зрения постоянного и удобного управления пользовательским интерфейсом как во время исполнения, так и во время разработки. Тем не менее, это вызвало эту проблему, которая может легко управлять другими аспектами интерфейса.

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

+0

Убедитесь, что вы поместили это в свой класс, который принимает форму в конструкторе. Он должен реализовать интерфейс IDisposable и быть отделенным по свойствам по завершении. Он также должен использовать отслеживание ссылок (увеличение/уменьшение целого числа, поэтому рекурсивный вызов его не вызовет проблем) и только скрывает элементы управления, когда это идет от 0 до 1. И только показывая их снова, когда он идет от 1 до 0. – TamusJRoyce 2011-10-03 13:55:12

+0

Получаете ли вы доступ к этим элементам управления извне из отдельного потока? – Tanerax 2008-08-12 14:50:43

ответ

19

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

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

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

+1

иногда соединение хорошо ... программист должен уметь решать. Вот почему защищенный доступ глупый. – 2011-07-26 03:04:53

2

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

36

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

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

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

7

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

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

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

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

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

0

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

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

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

0

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

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


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

1

Я согласен с использованием событий для этого. Поскольку я подозреваю, что вы создаете MDI-приложение (поскольку вы создаете много дочерних форм) и динамически создает окна и может не знать, когда отказаться от подписки на события, я бы рекомендовал вам взглянуть на Weak Event Patterns. Увы, это доступно только для фреймворков 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; 
} 
0

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

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

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

Он также будет намного проще писать юнит и приемочные испытания для, потому что вы можете следовать «Trust But Verify» образец при этом:

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

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

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

0

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

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

1

Вы можете

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

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

1

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

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

0

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

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

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

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

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

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

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

Но некоторые странные!

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

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

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

Или

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

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

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

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

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

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

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

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

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

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

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

.

внутренний статический класс A {

internal static FormC FrmC; 

}

FormB ... { . . .

A.FrmC = новый FormC();

. . .

FormC (файл конструктора). , , {

internal System.Windows.Forms.TextBox TextBox1; 

}

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


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

Спасибо и наилучшие пожелания

Мансур Бозоргмехр

[email protected]

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