2009-11-15 3 views
3

У меня есть приложение, которое в одной форме (Form1) У меня есть много checkbox и текстовых полей, а в Form2 У меня есть только текстовое поле, но я хочу поместить некоторое содержимое из текстовых полей Form1 и поставить в Form2 TextBox, как это, но между формами:Использование элементов управления одной формы в другой

textBox1.Text = "Test: " + textBox1 + "\n" + textBox3; 

textBox1 как в Form2 и второй textBox1 и textBox3 в Form1, но как я могу сделать это? Благодарю.

+0

imho было бы полезно выяснить, как именно Form1 и Form2 создаются: Form1 создает Form2 (возможно, что мы предположим, прочитав ваше сообщение); или, являются ли обе формы, созданные каким-либо другим классом или формой? best, – BillW

+1

Это только я или этот вопрос действительно непонятен? – claws

ответ

7

В зависимости от того, как вы запускаете вторую форму, вы можете назначить объект-член в Form2, который ссылается на Form1 или если вы используете интерфейс MDI, существует коллекция форм, из которой вы можете получить ссылку на свой Form1.

Например, вы могли бы иметь следующий код в вашем классе Form2:

public partial class Form2 : Form 
{ 
    public Form1 LaunchOrigin { get; set; } 
    // and so on 

Теперь вы можете назначить члена LaunchOrigin при запуске Form2. Вот пример:

Form2 newForm = new Form2(); 
newForm.LaunchOrigin = this; 
newForm.Show(); 

Теперь у вас есть доступ к Form1 и всем его членам. Вот простой пример:

private void Form2_Load(object sender, EventArgs e) 
    { 
     this.Text = LaunchOrigin.Text; 
    } 

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

public partial class Form1 : Form 
{ 
    public Button theButton; 
    public Form1() 
    { 
     InitializeComponent(); 
     theButton = button1; // where button1 is what I dragged on 
    } 
    // and so on 

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

7

Есть достойные способы сделать это и некрасивые способы сделать это ... начиная с UGLY:

  1. Один из самых уродливых было бы передать ссылку на Form1 в конструктор Form2 и затем сохранить эта ссылка как поле для дальнейшего. Это противно, потому что создает очень плотную связь между ними. Изменение интерфейса Form1 или поведения влияет на Form2.

  2. Менее уродливый, но все же хакерский способ сделать это будет передавать строковые значения из Form1 в конструктор Form2 - или некоторый общедоступный/внутренний метод в Form2. У вас все еще есть зависимость от этих строк, но по крайней мере это не полная связь Form1 и Form2. Это просто ожидание того, что Form2 всегда будет иметь Form1 для подачи этих строк.

... заполните здесь еще несколько неприятных вариантов.

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

Создайте интерфейс обмена сообщениями, который работает на легкой модели «pub/sub» - или publish/subscribe.Идея состоит в том, что у вас есть некоторые компоненты в вашем приложении, которые публикуют сообщения (ваши строковые значения или что-то более сложные) и другие компоненты вашего приложения, которые подписываются на сообщения.

Когда Form 1 запускается, он регистрируется в интерфейсе обмена сообщениями «Привет, я собираюсь публиковать сообщения этого типа» (где тип - это некоторый индикатор, который вы предоставляете). Когда Form 2 запускается, он регистрируется с помощью интерфейса обмена сообщениями «Yo, когда кто-то публикует сообщение такого типа, передайте его мне».

И издатель, и подписчик реализуют некоторый известный интерфейс, чтобы ваш обработчик сообщения мог разговаривать с ними (IPublisher, ISubscriber) - и получать/отправлять сообщения. Нет причин, по которым один компонент может быть как издателем, так и подписчиком, если это оправдано (в основном, рассматривая объекты в системе как «сверстники» или «коллеги»). Несколько событий MessageReceived и некоторый код для управления коллекцией издателей/подписчиков, хорошо идти.

Для получения более подробной информации, check out the Mediator pattern, который описывает этот тип решения более подробно.

+0

Зачем внедрять свою собственную паб/вспомогательную модель, когда вы можете использовать встроенную платформу событий .NET для этого? Кроме того, вам нужно только pub/sub между формами, если вы одновременно показываете несколько форм. В большинстве приложений простой объект «ApplicationData» может передаваться между формами для передачи данных. Это более простой подход и является первым шагом на разделении представления данных. – Ash

+0

Реализация паб/под модель в.NET * будет использовать модель событий .NET. Вы правы, что исходный плакат мог передать объект «Данные приложения» в качестве способа передачи параметров - это, безусловно, простой, чем подход, основанный на сообщениях. Однако изменения интерфейса для этого всеобъемлющего объекта «Данные приложения» требуют изменений как для отправителя, так и для получателя. Это просто зависит от компромиссов простоты/гибкости/сложности, требуемых в приложении. –

3

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

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

Вот простой пример того типа, который был полезен для меня в прошлом.

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

using System; 
using System.Collections.Generic; 
using System.Windows.Forms; 

// note : compiles against FrameWork 2.0 and 4.0 
// wanted this to work w/o Linq, automatic properties, etc. 

namespace MessageHandler 
{ 
    public static class TextBoxMessenger 
    { 
     // internal List of TextBoxes of interest on all Forms 
     internal static List<TextBox> _messageEnabledTBxes = new List<TextBox>(); 

     // public Property to get/set the collection of TextBoxes of interest 
     public static List<TextBox>MessageEnabledTextBoxes 
     { 
      get { return _messageEnabledTBxes; } 

      set { _messageEnabledTBxes = value; } 
     } 

     // in case you want to register one TextBox at a time 
     public static void RegisterTextBoxForMessaging(TextBox theTBx) 
     { 
      _messageEnabledTBxes.Add(theTBx); 
     } 

     // send from one specific TBx to another 
     public static void setText(TextBox originTBx, TextBox destinationTBx) 
     { 
      destinationTBx.Text = originTBx.Text; 
     } 

     // send to a specified list of TextBoxes 
     public static void setText(TextBox originTBx, List<TextBox> destinationTBxs) 
     { 
      foreach (TextBox theTBx in destinationTBxs) 
      { 
       theTBx.Text = originTBx.Text; 
      } 
     } 

     // set text in all other TextBoxes in MessageEnabledTextBoxes list 
     public static void setText(TextBox originTBx) 
     { 
      foreach (TextBox theTBx in _messageEnabledTBxes) 
      { 
       // a needless check, since assigning the text of the 
       // original TextBox to itself wouldn't "hurt" anything 
       // but, imho, much better "practice" to always test 
       if (theTBx != originTBx) theTBx.Text = originTBx.Text; 
      } 
     } 
    } 
} 

Так в действии, как это работает: давайте использовать пример, где ваш Form1 Событие загрузки выглядит так:

// assume Form2 has a single TextBox on it named 'textBox1' 
public Form2 myForm2; 

private void Form1_Load(object sender, EventArgs e) 
{ 
    myForm2 = new Form2(); 
    myForm2.Show(); 

    // register all the TextBoxes 

    // note the redundant use of 'this here : it's a deliberate choice to make 
    // the code communicate to a future user/reader/maintainter 
    TextBoxMessenger.RegisterTextBoxForMessaging(this.textBox1); 
    TextBoxMessenger.RegisterTextBoxForMessaging(this.textBox2); 
    TextBoxMessenger.RegisterTextBoxForMessaging((TextBox)myForm2.Controls["textBox1"]); 

    // or ... 
    //TextBoxMessenger.MessageEnabledTextBoxes = new List<TextBox> 
    //{ 
    // this.textBox1, this.textBox2, (TextBox)myForm2.Controls["textBox1"] 
    //}; 
} 

И вы можете проверить выше, как это, поставив кнопку на Form1:

private void button1_Click(object sender, EventArgs e) 
{ 
    // tests 

    // one to all ... 
    //TextBoxMessenger.setText(this.textBox1); 

    // one to a specific TextBox on another Form 
    //TextBoxMessenger.setText(this.textBox1, (TextBox) myForm2.Controls["textBox1"]); 

    // one to a List<TextBox> 
    TextBoxMessenger.setText(this.textBox1, new List<TextBox> { this.textBox2, (TextBox)myForm2.Controls["textBox1"]}); 
} 

Но, обратите внимание на «уродство», «плохой код запах,» таких вещей, как:

(TextBox) myForm2 .Controls ["textBox1"] // Кастинг - это зло! поставил кровавую ссылку!

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

Надеюсь, это полезно. В «долгосрочной перспективе» абстракция сообщения, передаваемого на более высокий уровень, который, как мне кажется, Джефф предписывает, - это imho, «королевский путь», чтобы сделать примеры кода более мощными и более «обобщаемыми», чем этот пример. best,

+0

Молодец. Спасибо, что добавили некоторые конкретные детали реализации в предложенный мной подход. Я думаю, что либо традиционный подход/рамки инъекции зависимости, либо подход к обмену сообщениями намного лучше, чем другие ответы, которые создают жесткую связь. Самое приятное в маршруте DI заключается в том, что переход с известной структурой не только решает эту проблему, но и может добавить большую ценность в другое место в приложении. –

0

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

например.

namespace SomeNamespace 
{ 
    public partial class Form2 : Form 
    { 
     string someStr = string.Empty; 

     public Form2() 
     { 
      InitializeComponent(); 
     } 

     public Form2(string params) // Parametrized Constructor 
     { 
      InitializeComponent(); 

      someStr = params 
     } 

     private void Form2_Load(object sender, EventArgs e) 
     { 
      Form2TextBox.Text = someStr ; 
     } 
    } 
} 

Теперь из Form1 Form2 называют таким образом

Form2 objF2 = new Form2(Form1TextBox1.Text); 
objF2.Showdialog(); 
1

Этот вопрос, или вариации него, как было предложено много раз на StackOverflow. Я думаю, что это вызвано непониманием о Forms и дизайнере Visual Studio.

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

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

Затем для каждой формы, которая должна получить доступ к данным, добавьте общедоступное свойство get/set типа ApplicationData. Наконец, установите это свойство в объект ApplicationData непосредственно перед показом каждой формы.

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

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

class ApplicationData{ 
    private string _firstName; 
    public string FirstName; 
    { 
     get { return _firstName;; } 
     set { __firstName;=value; } 
    } 

    private string _lastName; 
    public string LastName; 
    { 
     get { return _lastName; } 
     set { __lastName=value; } 
    } 
} 

class ChildForm : Form 
{ 
    private ApplicationData _applicationData=null; 

    public ApplicationData AppData 
    { 
     get { return _applicationData; } 
     set { _applicationData=value; } 
    } 

    void Load_Form(object sender, EventArgs args) 
    { 
     txtFirstName.Text=AppData.FirstName; 
     txtLastName.Text=AppData.LastName; 
    } 

    void Form_Closing(object sender, EventArgs args) 
    { 
     AppData.FirstName=txtFirstName.Text; 
     AppData.LastName=txtLastName.Text; 
    } 

} 

class MainForm : Form 
{ 
    private ApplicationData _applicationData=new ApplicationData(); 

    void Button_Click(object sender, EventArgs args) 
    { 
     ChildForm childForm=new ChildForm(); 

     ChildForm.AppData=_applicatonData; 

     ChildForm.ShowDialog(); 

     string fullName=_applicatonData.LastName + " " + _applicatonData.FirstName 
    } 
} 

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

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

Шаблон проектирования создания и использования класса «ApplicationData» - это первый шаг к отделению презентации от вашего контента. Позор Visual Studio не дает больше рекомендаций в этой области.

Смежные вопросы