2009-11-03 17 views
29

Tengo dos formularios, uno es el formulario principal y el otro es un formulario de opciones. Por ejemplo, supongamos que el usuario hace clic en mi menú en el formulario principal: Tools -> Options, esto haría que se mostrara mi formulario de opciones.Comunicar entre dos formularios de Windows en C#

Mi pregunta es ¿cómo puedo enviar los datos de mi formulario de opciones a mi formulario principal? Sé que podría usar propiedades, pero tengo muchas opciones y esto me parece extraño tedioso cosa que hacer.

Entonces, ¿cuál es la mejor manera?

+0

@Bob: ¿Está cerrando sus opciones de Formulario después de establecer las opciones y quiere que el formulario principal se abra con los valores de las opciones? – RKh

+0

@Rohit: básicamente, sí. –

Respuesta

50

Form1 activa Form2 para abrir. Form2 ha sobrecargado el constructor que toma la forma de llamada como argumento y proporciona su referencia a los miembros de Form2. Esto resuelve el problema de comunicación. Por ejemplo, he expuesto Label Property como público en Form1, que se modifica en Form2.

Con este enfoque puede hacer la comunicación de diferentes maneras.

Download Link for Sample Project

// Su Form1

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

    private void button1_Click(object sender, EventArgs e) 
    { 
     Form2 frm = new Form2(this); 
     frm.Show(); 
    } 

    public string LabelText 
    { 
     get { return Lbl.Text; } 
     set { Lbl.Text = value; } 
    } 
} 

// Su Form2

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

    private Form1 mainForm = null; 
    public Form2(Form callingForm) 
    { 
     mainForm = callingForm as Form1; 
     InitializeComponent(); 
    } 

    private void Form2_Load(object sender, EventArgs e) 
    { 

    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     this.mainForm.LabelText = txtMessage.Text; 
    } 
} 

alt text http://demo.ruchitsurati.net/files/frm1.png

alt text http://demo.ruchitsurati.net/files/frm2.png

+0

¡Respuesta impresionante! Eso es exactamente lo que estoy buscando! ¡Gracias! También me encanta que los negro en XP (casi me hace perder XP). –

+1

Es el tema de Zune para XP. :) –

+4

Esto conduce a un acoplamiento estricto de los formularios Form1 y Form2, supongo que uno debería usar eventos personalizados para ese tipo de escenarios. –

1

Propiedades es una opción, compartida clase estática - otra opción, eventos - otra opción ...

+0

Argumentos al constructor, llamadas a métodos, ... :-) – Joey

+0

MVP, MVC, MVVM ... –

5

Lo mejor en este caso sería tener alguna OptionsService clase/interfaz que es accesible a través de IServiceProvider.

Simplemente agregue un evento cuando algo cambie y el resto de la aplicación pueda responder.

1

Puede probar AutoMapper. Mantenga sus opciones en una clase separada y luego use AutoMapper para transferir los datos entre la clase y el formulario.

1

crear una clase y poner todas sus propiedades dentro de la clase .. Crear una propiedad de la clase padre y configurarlo de su hijo (opciones) de forma

1

Puede tener una función en la forma B de esta manera:

public SettingsResults GetNewSettings() 
{ 
    if(this.ShowDialog() == DialogResult.Ok) 
    { 
     return new SettingsResult { ... }; 
    } 
    else 
    { 
     return null; 
    } 
} 

Y se le puede llamar así:

... 
using(var fb = new FormB()) 
{ 
    var s = fb.GetNewSettings(); 
    ... 
    // Notify other parts of the application that settings have changed. 
} 
0

esta es, probablemente, esquivando su problema un poco, pero mi diálogo de configuración utiliza la configuración de aplicación construir. http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx

no puedo encontrar un buen ejemplo que es similar a cómo lo hago (que en realidad está teniendo una clase real + objeto), pero esto cubre otra forma de hacerlo:

Reading default application settings in C#

+0

Esto es bueno, pero no estoy interesado en almacenar la configuración. Solo quiero que estas configuraciones sean retransmitidas a la forma principal. –

0

Un formulario es una clase, como cualquier otra clase. Agregue algunas variables públicas a su clase de formulario y configúrelas cuando hagan clic en el botón para cerrar el formulario (técnicamente solo lo están ocultando).

Un ejemplo VB.NET, pero usted consigue la idea -

En su clase de OptionsForm:

Public Option1 as String = "" 

etc. Ajuste ellos cuando se pulsa el botón "OK".

Así que en su forma principal, cuando se pulsa el botón "Opciones" - crear sus opciones formulario:

OptionsForm.ShowDialog() 

cuando sale, se cosecha la configuración de opciones de las variables públicas en la forma:

option1 = OptionsForm.Option1 

etc.

1

MVC, MVP, MVVM - ligero exceso para alguien que dice que quiere tutoriales. Esas son teorías que tienen cursos enteros dedicados a ellos.

Como ya se ha publicado, probablemente sea más fácil pasar un objeto. Si el tratamiento de una clase como un objeto (intercambiable en este sentido) es nuevo, entonces es posible que desee pasar otras 2-4 semanas averiguando propiedades y constructores, etc.

No soy maestro de C# de ninguna manera, pero estos conceptos deben ser bastante concretos si quieres ir mucho más allá de pasar valores entre dos formas (también clases/objetos por derecho propio). No tratando de ser malo aquí en absoluto, suena como si estuvieras pasando de algo como VB6 (o cualquier lenguaje con globales) a algo mucho más estructurado.

Eventualmente, hará clic.

8

En los comentarios a la respuesta aceptada, Neeraj Gulia escribe:

Esto lleva a acoplamiento hermético de las formas Form1 y Form2, supongo que en su lugar se debe usar eventos personalizados para este tipo de escenarios.

El comentario es exactamente el correcto. La respuesta aceptada no está mal; para programas simples, y especialmente para personas que recién están aprendiendo programación e intentando que funcionen escenarios básicos, es un ejemplo muy útil de cómo un par de formularios puede interactuar.

Sin embargo, es cierto que el acoplamiento que causa el ejemplo puede y debe evitarse, y que en el ejemplo particular, un evento podría lograr lo mismo de forma desacoplada y de propósito general.

He aquí un ejemplo, utilizando el código de la respuesta aceptada como línea de base:

Form1.cs:

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

    private void button1_Click(object sender, EventArgs e) 
    { 
     Form2 frm = new Form2(); 

     frm.Button1Click += (sender, e) => Lbl.Text = ((Form2)sender).Message; 

     frm.Show(); 
    } 
} 

El código anterior crea una nueva instancia de Form2, y luego antes de mostrarlo, agrega un controlador de eventos al evento Button1Click de ese formulario.

Tenga en cuenta que la expresión (sender, e) => Lbl.Text = ((Form2)sender).Message se convierte automáticamente por el compilador a un método que se ve algo similar a (pero definitivamente no exactamente) lo siguiente:

private void frm_Message(object sender, EventArgs e) 
{ 
    Lbl.Text = ((Form2)sender).Message; 
} 

En realidad, hay un montón de maneras/sintaxis para implementar y suscribe el controlador de eventos. Por ejemplo, usando un método anónimo como el anterior, realmente no necesita lanzar el parámetro sender; en su lugar, puede usar la variable local frm directamente: (sender, e) => Lbl.Text = frm.Message.

Yendo en sentido contrario, no es necesario utilizar un método anónimo. De hecho, puede declarar un método regular como el generado por el compilador que muestro arriba, y luego suscribir ese método al evento: frm.Button1Click += frm_Message; (donde por supuesto usó el nombre frm_Message para el método, tal como en mi ejemplo anterior)

Independientemente de cómo lo hace, por supuesto que se necesitan para Form2 a aplicar en la práctica que Button1Click evento. Eso es muy simple y hellip;

Form2.cs:

public partial class Form2 : Form 
{ 
    public event EventHandler Button1Click; 

    public string Message { get { return txtMessage.Text; } } 

    public Form2() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     EventHandler handler = Button1Click; 

     if (handler != null) 
     { 
      handler(this, EventArgs.Empty); 
     } 
    } 
} 

Además del evento, también han declarado una propiedad Message que expone la propiedad Text (y única la propiedad Text, y sólo como lectura solo de hecho) del control txtMessage. Esto permite que el suscriptor del evento obtenga el valor y haga lo que necesite con él.

Tenga en cuenta que todo lo que hace el evento es alertar al suscriptor de que se ha hecho clic en el botón. Depende del suscriptor decidir cómo interpretar o reaccionar ante ese evento (por ejemplo, recuperando el valor de la propiedad Message y asignándola a algo).

Como alternativa, puede de hecho entregar el texto junto con el evento en sí, declarando una nueva EventArgs sub-clase y el uso que para el evento en su lugar:

public class MessageEventArgs : EventArgs 
{ 
    public string Message { get; private set; } 

    public MessageEventArgs(string message) 
    { 
     Message = message; 
    } 
} 

public partial class Form2 : Form 
{ 
    public event EventHandler<MessageEventArgs> Button1Click; 

    public Form2() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     EventHandler handler = Button1Click; 

     if (handler != null) 
     { 
      handler(this, new MessageEventArgs(txtMessage.Text)); 
     } 
    } 
} 

A continuación, el abonado puede simplemente recuperar el mensaje valor directamente desde el objeto de evento:

frm.Button1Click += (sender, e) => e.Message; 


lo importante nota en todos t Las variaciones anteriores es que en ningún momento la clase Form2 necesita saber nada sobre Form1. Tener Form1 saber acerca de Form2 es inevitable; después de todo, ese es el objeto que creará una nueva instancia de Form2 y la usará. Pero la relación puede ser asimétrica, con Form2 utilizable por cualquier objeto que necesite las características que ofrece. Al exponer la funcionalidad como un evento (y opcionalmente con una propiedad), se vuelve útil sin limitar su utilidad a la clase Form1.

0

Hay muchas maneras de realizar la comunicación entre dos formularios. Algunos de ellos ya han sido explicados. Te estoy mostrando al revés.

Suponiendo que tiene que actualizar algunas configuraciones desde el formulario secundario al formulario principal. Puede hacer uso de estas dos maneras también:

  1. Usando System.Action (Aquí simplemente pasan a la función principal de las formas como parámetro a la forma niño como una función de devolución de llamada) Método
  2. OpenForms (usted directamente llamar a uno de sus formas abiertas)

Usando System.Action

puede pensar en ella como una función de devolución de llamada se pasa al formulario secundario.

// -------- IN THE MAIN FORM -------- 

// CALLING THE CHILD FORM IN YOUR CODE LOOKS LIKE THIS 
Options frmOptions = new Options(UpdateSettings); 
frmOptions.Show(); 

// YOUR FUNCTION IN THE MAIN FORM TO BE EXECUTED 
public void UpdateSettings(string data) 
{ 
    // DO YOUR STUFF HERE 
} 

// -------- IN THE CHILD FORM -------- 

Action<string> UpdateSettings = null; 

// IN THE CHILD FORMS CONSTRUCTOR 
public Options(Action<string> UpdateSettings) 
{ 
    InitializeComponent(); 
    this.UpdateSettings = UpdateSettings; 
} 

private void btnUpdate_Click(object sender, EventArgs e) 
{ 
    // CALLING THE CALLBACK FUNCTION 
    if (UpdateSettings != null) 
     UpdateSettings("some data"); 
} 

OpenForms Método

Este método es fácil (2 líneas). Pero solo funciona con formularios que están abiertos. Todo lo que necesita hacer es agregar estas dos líneas donde quiera que quiera pasar algunos datos.

Main frmMain = (Main)Application.OpenForms["Main"]; 
frmMain.UpdateSettings("Some data"); 
Cuestiones relacionadas