[How to] Pasar datos de Form hijo a Form padre

Hoy en la mañana el amigo Julio Avellaneda me planteó la duda de cómo pasar información de un Form hijo (al estilo modal) a un Form principal (padre). Bien, pues esta es una duda recurrente, la comunicación entre Forms es algo que siempre es muy discutido y necesario en nuestras aplicaciones, en un post anterior vimos como pasar información entre dos WinForms, y faltó una técnica, que es sin duda una de las más pro.

Para comunicar un Form hijo con uno padre que ya está instanciado es necesario hacer uso de las interfaces, con el objetivo de que exista algo de “intermedio” que permita su comunicación “indirecta”.

Para el desarrollo de este ejemplo tendremos dos WinForms, siendo Form1 el Form padre y Form2 el Form hijo, en el Form1 agregaremos un TextBox y un Button, al Textbox le cambiaremos la propiedad ReadOnly a true (impedir su escritura). En el Form2 agregamos lo mismo un Button y TextBox. Por último agregamos una nueva interfaz que llamaremos IForm.

El uso de esta interfaz nos permitirá desacoplar la comunicación entre los dos WinForms, para esto creamos un miembro que reciba como parámetro el valor string que deseamos asignar, así:

public interface IForm
{
        void cambiarTexto(string text); 
}

Una vez construida la interfaz, vamos a utilizarla en nuestros Forms, en el Form1 (Form padre), implementamos la interfaz que hemos creado, así:

public partial class Form1 : Form, IForm
{
        public Form1()
        {
            InitializeComponent();
        }
        public void cambiarTexto(string text)
        {
            textBox1.Text = text;
        }
}

Ahora en el Form2 (Form hijo), en el evento del botón enviar texto declaramos un objeto de la interfaz y le asignamos el Form definido como hijo siendo este casteado al tipo de la interfaz, luego simplemente apuntamos al miembro y pasamos el valor, así:

private void button1_Click(object sender, EventArgs e)
{
            IForm miInterfaz = this.Owner as IForm;
            if (miInterfaz != null)
                miInterfaz.cambiarTexto(textBox1.Text);
            this.Dispose();
} 

De esta forma se comunican de form hijo a form padre, usando “algo de intermedio” que nos permita la comunicación desacoplada.

Descarga el ejemplo.

Espero les sea de utilidad.

Hasta el próximo post.

Anuncios
[How to] Pasar datos de Form hijo a Form padre

[How to] TextBox con Autocompletar

A menudo en nuestras aplicaciones, queremos facilitarle la vida a los usuarios (aún más), entonces para mejorar la experiencia de uso de nuestros programas quisiéramos que los usuarios no tuvieran que digitar nada, o por lo menos, que fuera muy poco, para esto .NET tiene la solución, el control TextBox tiene unas propiedades espectaculares que facilitan este trabajo.

Para este ejemplo, crearemos una aplicación de WinForms, y arrastramos un TextBox a su interior (textBox1), no necesitamos más para probar esta funcionalidad.

El autocomplete de este control lo puedes trabajar de muy variadas formas, la mejor, es haciéndolo desde un origen de datos y asignándolo mediante código, así agregas dinamismo a la solución.

Para este ejemplo, crearé un método del tipo List, que nos retorna una lista de países, así:

private List getPaises()
{
      var listPaises = new List<string>();
      listPaises.Add("Colombia");
      listPaises.Add("Venezuela");
      listPaises.Add("Ecuador");
      listPaises.Add("Peru");
      listPaises.Add("Brasil");
      return listPaises;
}

A este método acudiremos desde el evento Load de nuestro Form, de la siguiente forma:

private void Form1_Load(object sender, EventArgs e)
{
      var allPaises = getPaises();            
}

Una vez que tenemos nuestro origen de datos empezamos a trabajar con las propiedades del TextBox que nos permiten la funcionalidad de autocompletar, la primera propiedad que trabajaremos será la AutoCompleteMode esta propiedad establece el “efecto visual” que tendrá nuestro autocomplete, sus valores pueden ser:

Append: Autocompleta en la misma línea mediante se va escribiendo:

Autocompletmode Append

None: Sin autocompletar, pese a que agreguemos el origen de datos, este valor impide el autocompletar

Suggest: Ofrece las opciones en un “desplegable” abajo del control:

Autocompletemode.Suggest

 SuggestAppend: Se aplica tanto a Suggest como a Append. 

Como deseamos que nuestro TextBox autocomplete a partir de una lista de datos propia, trabajaremos con la propiedad AutoCompleteCustomSource, esta propiedad es del tipo AutoCompleteStringCollection, es decir, solo le podemos asignar valores de este tipo, para esto nos creamos un objeto de esta clase y le agregamos nuestra lista de datos, así:

private void Form1_Load(object sender, EventArgs e)
{
     var allPaises = getPaises();
     textBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend; //Es el mas bonito
     AutoCompleteStringCollection accl = new AutoCompleteStringCollection();            
     accl.AddRange(allPaises.ToArray()); //convertimos la lista en un Array    
}

Ahora solo falta asignarle al TextBox nuestro el origen de datos para autocompletar, para esto acudimos a la propiedad ya mencionada (AutoCompleteCustomSource) y definimos el modo de autocompletado a usar, esto lo definimos en la propiedad AutoCompleteSource, así:

private void Form1_Load(object sender, EventArgs e)
{
      var allPaises = getPaises();
      textBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
      AutoCompleteStringCollection accl = new AutoCompleteStringCollection();            
      accl.AddRange(allPaises.ToArray());
      textBox1.AutoCompleteCustomSource = accl;
      textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
} 

De este modo podemos actualizar con una lista de datos propios ¿Pero si deseas que autocomplete con direcciones URL p. ej.? basta con redefinir el valor de la propiedad AutoCompleteSource por AllUrl, así:

textBox1.AutoCompleteSource = AutoCompleteSource.AllUrl;

Puedes usarlo como desees, explóralo y sácale el potencial.

Descarga el ejemplo

Espero les sea de utilidad

Hasta el próximo post.

[How to] TextBox con Autocompletar

[HowTo] ¿Como pasar datos entre dos Windows Forms?

En los foros de C#, ésta es una pregunta habitual, y no es para menos, si apenas comienzas con el lenguaje tareas como esta se dificultan, es por eso que me he decidido a hacer este post, para mostrar las soluciones que he encontrado a tan habitual problema, describiendo sus pros y sus contras en qué casos sí y en qué casos no es bueno aplicarlas.

El escenario es: ¿Cómo pasar los datos de una variable que está en un Form a otro? Para el desarrollo de los ejemplos he agregado dos Windows Forms a una aplicación Windows Forms en C#, en el Form1 he agregado un botón (button1) y el Form2 sin ningún control.

La primera de las soluciones que empleé, fue declarar variables públicas en el form que recibe los datos (a partir de ahora Form2) y alterar su valor desde la instancia del form que envía la información (a partir de ahora Form1). En la clase del Form2, tengo una variable pública que recibe la info del form1 y en su evento Load público un MessageBox con la variable:

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

        public string recibir_datos; //variable del tipo de dato que necesites pasar, en el caso del ejemplo sera string
        private void Form2_Load(object sender, EventArgs e)
        {
            MessageBox.Show(recibir_datos); //Mostrar valor de la variable
        }
}

Si lo ejecutas, al dar clic en el botón del Form1 te mostrará un MessageBox con el valor de la variable que pasamos, “lo logramos”. Peroooo… el que funcione no quiere decir que sea lo mejor ¿Por qué?, pues porqué en este caso simplemente pasamos un string sin sentido, pero recuerda que la variable ES PÚBLICA, es decir, esta propiedad es visible para cualquier clase que acuda a ésta (Form2), lo que nos genera problemas de seguridad.
Teniendo claro esto, pensé en una segunda opción, en la que la propiedad no quedara visible a las otras clases.
En el Form2 “pido” como parámetro al variable en el método de la clase (public Form2()) y se lo asigno a una variable privada dentro de esta clase, así:

private string recibir_datos; //Declaracion de la variable con modificador de acceso PRIVADO 

public Form2(string el_parametro) // se solicita un parametro del tipo string en el metodo de la Clase 
{
            InitializeComponent();
            recibir_datos = el_parametro; //se asigna el valor del parametro a la variable privada.
}

private void Form2_Load(object sender, EventArgs e)
{
            MessageBox.Show(recibir_datos); //Se muestra el valor de la variable privada
}

¡Funciona! y  es seguro, a decir verdad, es una solución simple y elegante, pues ocultamos el valor de la propiedad de las demás clases que pudiesen acceder a este. Perooo, a esta le he encontrado un problema, y es que este parámetro es obligatorio, es decir, siempre se va a pedir este valor en el constructor ¿Y si no queremos pasar ningún valor desde el Form3 (p. ej)? Sería poco elegante de nuestra parte pasar datos al azar, o que no tengan nada que ver. Por fortuna para nosotros C# soporta SOBRECARGA, en realidad todos los lenguajes orientados a objetos lo hacen, esto nos da la posibilidad de tener  dos métodos con el mismo nombre pero con distinta cantidad de argumentos, es decir, podemos o no, pasar el dato a el constructor. Para esto alteramos nuestro Form2 levemente:

private string recibir_datos;
 public Form2() //Metodo de la clase sin parametros
 {
 InitializeComponent();
 }
 public Form2(string el_parametro) //Metodo de la clase que espera un parametro
 {
 InitializeComponent();
 recibir_datos = el_parametro;
 }
 private void Form2_Load(object sender, EventArgs e)
 {
 if(!string.IsNullOrEmpty(recibir_datos))  //Por cuestiones de elegancia, si la variable esta vacia NO MUESTRA MENSAJE
 MessageBox.Show(recibir_datos);
 }

En el Form1 he agregado otro botón (button2) en el que no se pasará parámetro en el constructor, así:

private void button1_Click(object sender, EventArgs e)
{
            string variable = "Texto enviado de un form a otro"; 
            Form2 frm2 = new Form2(variable); //Pasando Variable en el constructor            
            frm2.Show();            
}
private void button2_Click(object sender, EventArgs e)
{
            Form2 frm2 = new Form2(); //sin variable en el constructor
            frm2.Show();            
}

Ésta es mucho mas elegante y segura, no le he encontrado ningún problema, pero si una limitación, la sobrecarga solo nos admite métodos con distinto tipo de argumentos, es decir, no podemos tener dos métodos con el mismo nombre, la misma cantidad de parámetros y del mismo tipo. Para esta limitación, la solución es muy simple, nos creamos un método propio en el Form2 que le de el valor a la variable y listo. El código queda así:

private string recibir_datos;

public void setearvariable(string el_otro_parametro) //Método del tipo void (no retorna valor)
{
            recibir_datos = el_otro_parametro; //asignar variable privada lo que tenga el parámetro
}
private void Form2_Load(object sender, EventArgs e)
{
            if(!string.IsNullOrEmpty(recibir_datos))
                MessageBox.Show(recibir_datos);  //Publica datos si esta no viene vacía          
}

Espero les sea de utilidad.

Descarga el ejemplo

Hasta el próximo post.

[HowTo] ¿Como pasar datos entre dos Windows Forms?