sábado, 19 de septiembre de 2009

C# – AutoComplete ComboBox o TextBox

 

Introducción


Muchas veces es necesario exponer al usuario herramientas de búsqueda que le faciliten la interacción con la aplicación que desarrollamos.

Una de estas herramientas es precisamente el AutoComplete, por el cual el usuario podrá ir visualizando los ítems existentes a medida que se escribe en un control.

TextBox AutoComplete


Hacer uso de las opciones de autocomplete de estos controles es bastante simple, solo hace falta especificar un par de propiedades, pero hay que tener en cuenta algunos puntos.

Estas propiedades son:

AutoCompleteSource

AutoCompleteMode

AutoCompleteCustomSource

textBox1.AutoCompleteCustomSource = DataHelper.LoadAutoComplete();
textBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
textBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;

En el ejemplo se visualiza como asignar estas propiedades, pero debe prestarse atención a la propiedad “AutoCompleteCustomSource” esta es clave, pues contendrá la lista de ítems.

Esta propiedad es justamente uno de los puntos a tener en cuenta, ya que requiere cargar una lista de ítems que provenga de una colección del tipo “AutoCompleteStringCollection”

Es por ello que en el ejemplo se visualiza la generación de los datos que cargaran esta colección

public static AutoCompleteStringCollection LoadAutoComplete()
{
    DataTable dt = LoadDataTable();

    AutoCompleteStringCollection stringCol = new AutoCompleteStringCollection();

    foreach (DataRow row in dt.Rows)
    {
        stringCol.Add(Convert.ToString(row["Nombre"]));
    }

    return stringCol;
}

El código es bastante simple de entender, se obtiene los datos desde la db y como siguiente paso los recorre cargando la lista de ítems del autocomplete.

ComboBox AutoComplete


La utilización de las opciones de autocomplete de un control Combobox son idénticas a las de un TextBox, solo difiere en que el combo requiere cargar sus ítems previamente para la selección por parte del usuario.

O sea el combobox requiere dos listas para bindear

- una normal que se asignara al DataSource, y en donde se especificara tanto el valor a desplegar como el valor de la key

- una especial con la lista de descripciones para el autocomplete

//
// Cargo los datos del combobox
//
comboBox1.DataSource = DataHelper.LoadDataTable();
comboBox1.DisplayMember = "Nombre";
comboBox1.ValueMember = "Id";

//
// cargo la lista de items para el autocomplete
//
comboBox1.AutoCompleteCustomSource = DataHelper.LoadAutoComplete();
comboBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
comboBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;

Conclusión


El autocomplete es una excelente opción para ayudar al usuario en la interacción con la aplicación brindándole un fácil acceso mientras escribe la búsqueda.

 

[C#] 
[VB.NET] 

sábado, 12 de septiembre de 2009

[Winform] Realizar tareas antes de inicializar aplicación

 

Introducción


Algunas veces en las aplicaciones es necesarios desplegar una ventana de login, o un formulario de inicio, o ambos, esto genera un gran problema cuando la aplicación esta iniciada, ya que la ventana principal del formulario se encuentra visible. La idea es poder realizar operaciones previas a la visualización de la pantalla definida como principal.

Es por ello que existe un área (o método) previa al inicio, en donde se puede realizar operaciones previas al inicio de la aplicación.

Esta función tiene el nombre de Main()

 

C# – Main


Cuando se crea una “Windows Applicacion”, se podrá apreciar una clase de nombre: Program.cs

Esta clase es clave para poder realizar trabajos previos.

De forma inicial encontrara código similar al siguiente:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form1());
}

Las aplicaciones Windows en C#, siempre inician en un método Main.

Por supuesto podrá acomodarse para que realice algunas tareas previas, como ser, el mostrar un cuadro de login:

[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    //
    // Realizo la apertura del formulario para validar el login
    // esta tarea es previa al inicio de la aplicacion
    //
    frmLogin login = new frmLogin();
    login.ShowDialog();

    //
    // Si el login es correcto, procedo con la apetura normal
    // de la aplicacion
    //
    if (login.DialogResult == DialogResult.OK)
        Application.Run(new frmPrincipal());

}

Como se observa en el código en las líneas 11 y 12, se incia un nuevo formulario, que tendrá la responsabilidad de de la autenticación de usuario.

Dependiendo del resultado de la operación previa es que se dará inicio, o no, al hilo principal de la aplicación.

Algunos puntos interesantes a destacar:

  • Es necesario que los formulario previos realicen una pausa en la ejecución de método Main(), es por eso que se hace uso del ShowDialog() para mostrar el formulario de login. En este caso el simple Show() no podrá ser utilizado ya que este no produce un stop, sino que deja al método Main() continuar su ejecución
  • El código de las líneas 4 y 5 siempre serán las primeras líneas del método  Main(), ya que estas deben ejecutarse previas al despliegue de cualquier formulario
  • Como se observara en ningún momento se hizo uso de alguna funcionalidad de exit, o quit que cerrara la aplicación, simplemente con evitar pasara por la asignación de un formulario en Application.Run(), fue suficiente.

 

VB.NET – Sub Main


Si bien la explicación de este método en C# es bastante similar a la de VB.NET, deben remarcarse algunas diferencias que son fundamentales para lleva a cabo la tarea de forma correcta.

En principio al crear la Windows Application en VB.NET, esta no creara el archivo de clase “Program”, o similar, como si se hace en C# de forma automática. Es por eso que la creación de la clase deberá hacerse de forma manual.

En el ejemplo se visualizará una clase de nombre “SubMain.vb”, y dentro de esta el siguiente código:

<STAThread()> _
Shared Sub Main()

    Application.EnableVisualStyles()
    Application.SetCompatibleTextRenderingDefault(False)

    Dim login As frmLogin = New frmLogin
    login.ShowDialog()

    If (login.DialogResult = DialogResult.OK) Then

        Application.Run(New frmPrincipal)

    End If

End Sub

Como verán es prácticamente idéntico método Main() codificado en C#.

Bien hasta aquí todo perfecto, pero falta un paso mas que tal vez no sea tan obvio como parece.

Resulta que para que la aplicación VB.NET pueda tomar el método Main() como inicio hay que desmarcar la el check de nombre “Enable Application framework”

VB.NET SubMain Startup

Como se observa en la imagen, este check esta desmarcado y es en ese momento en donde se puede cambiar en el combo “Startup object” al método Sub Main.

En este link: Cómo: Cambiar el objeto inicial de una aplicación (Visual Basic)

Se encontrará una explicación mas amplia del tema.

 

Conclusión


Haciendo uso de método Main() se puede realizar operaciones previas a la carga del formulario principal de la aplicación de una forma simple y prolija.

 

[C#] 
[VB.NET] 

domingo, 6 de septiembre de 2009

Comunicar formularios MDI

 

Introducción


Este post representa la continuación de Comunicar formularios de forma desacoplada

Pero a diferencia del anterior en esta oportunidad se trabajara con formularios MDI

 

Diferencias


Al hacerse uso de formularios MDI, algo que ya no podrá ser utilizado es el parámetro Owner en el método Show(), al realizar la apertura del formulario hijo.

Es por ello que será necesito hacer uso de una propiedad en el formulario hijo para salvar este inconveniente, y poder así determinar que formulario esta ejecutando la acción de apertura.

 

Primer Paso – Definición de la interfaz

A diferencia el ejemplo anterior en este oportunidad se hará uso de un valor algo mas complejo que simple texto en la comunicación, es por ello el uso de un objeto DataTable como medio de transporte de datos entre los formularios.

Aunque nada impediría que se utilices clases custom creadas por uno.

public interface IForm
{
    bool LoadDataGridView(DataTable dataTableParam);
}

En este caso la interfaz también retorna un valor que indicará si el procesamiento se realizó correctamente.

 

Segundo Paso – Definición del formulario padre

Al igual que en el anterior post el formulario padre deberá implementar una interfaz, la cual permitirá desacoplar la dependencia durante la comunicación.

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

    #region IForm Members

    public bool LoadDataGridView(DataTable dataTableParam)
    {
        DataGridView1.DataSource = dataTableParam;

        return true;
    }

    #endregion


    private void Button1_Click(object sender, EventArgs e)
    {
        Form2 form2 = new Form2();

        form2.MdiParent = this.MdiParent;

        form2.Opener = this;

        form2.Show();
    }

}

Debe remarcarse algunos detalles, como es en este caso el uso de la propiedad MdiParent, que por supuesto siempre hará referencia al FormPrincipal, y que este ha sido declarado como MdiContainer

También hay que marcar la línea 26, en donde se visualiza el uso de la propiedad adicional, en este caso llamada Opener, es en esta donde se asignara el form que realizo la apertura del formulario.

 

Tercer paso – Definición del formulario hijo

Este formulario simplemente tendrá un botón que realizará el cierre de si mismo, pero durante esta operación se generarán los datos que serán pasados al formulario que se registro en la propiedad Opener.

Si bien este es un ejemplo, la misma técnica podría ser utilizada para realizar distintas acciones y pasaje de datos entre formularios.

public partial class Form2 : Form
{
    public IForm Opener { get; set; }

    public Form2()
    {
        InitializeComponent();
    }

    private DataTable LoadDataTable()
    {

        DataTable dt = new DataTable();

        dt.Columns.Add("Id");
        dt.Columns.Add("Nombre");

        for(int i=0 ; i <= 4; i++){
            DataRow row = dt.NewRow();

            row["Id"] = i;
            row["Nombre"] = String.Format("Nombre {0}", i);

            dt.Rows.Add(row);

        }

        return dt;
    }

    private void Button1_Click(object sender, EventArgs e)
    {
        this.Close();
    }

    private void Form2_FormClosing(object sender, FormClosingEventArgs e)
    {
        DataTable dataTable = LoadDataTable();

        bool estadoOperacion = this.Opener.LoadDataGridView(dataTable);

        e.Cancel = !estadoOperacion;
    }

}

La línea 3 define la propiedad Opener cuya utilización se visualizo en el código del Form1, la declaración de la misma utiliza el concepto de propiedades autoimplementadas.

La interacción entre formularios retorna un resultado que el formulario hijo utilizara para saber si debe proseguir con el cierre del formulario o cancelarlo.

En este simple ejemplo el formulario padre retorna siempre un estado satisfactorio de la operación, pero podría ser utilizado para capturar errores e informarlo al formulario hijo de esta situación.

 

Conclusión


La interacción entre formulario en un entorno MDI requiere de ciertas modificaciones al uso normal de iteración entre estos, igualmente la idea básica no es afectada.

Solo la imposibilidad de definir un formulario como owner añadió cierta complejidad al ejemplo, pero fue salvada con el uso de propiedades.

 

[C#] 
[VB.NET] 

Comunicar formularios de forma desacoplada

Introducción


El objetivo de esta guía es demostrar como posibilitar la comunicación de formulario de una forma optima, haciendo uso de buenas practicas, y además bajando al mínimo el acoplamiento entre los formulario.

Para cumplir el objetivo es que se hará uso de interfaces, las cuales permitirán desacoplar la comunicación entre formulario.

 

Comunicación simple entre formularios


En este ejemplo se confeccionara una utilidad simple, básicamente se procederá a la apertura de un formulario, y la escritura cuadros de texto.

 

Primer Paso – Creación de los formularios

Lo primero que será necesario crear son los dos formulario los cuales intervendrán en la comunicación, esta operación se hace de forma simple como seguramente ya es conocida por todos. Los mismos contaran con sus respectivos cuadros de texto, y botones que permitirán las acciones entre ellos

 

Segundo Paso - Definición de la interfaz

En al interfaz se definirá la acción que será llevada a cabo en la comunicación, en este caso sera algo simple como copiar el contenido del formulario hijo al padre

Para ello se ha creado un archivo de nombre IForm.cs, el cual contendrá dicha definición.

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

como podrá preciarse es muy simple solo define el contrato que permitirá luego desacoplar las interfaces

 

Tercer Paso – Implementación de la interfaz, llamada al formulario hijo

La interfaz anteriormente creada será implementada por el formulario del cual se quiere recibir la acción, en este caso será el form principal, o sea quien realiza la llamada.

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

    #region IForm Members

    public void ChangeTextBoxText(string text)
    {
        TextBox1.Text = text;
    }

    #endregion

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

Hay que resaltar varias partes en esta sección de código:

- se notara en la primer línea como el formulario define la implementación de la interfaz

- la región establecida en el código, denota la implementación concreta de la misma, entre las líneas 8 al 15

También hay que remarcar como se realiza la apertura del formulario hijo, debe notarse el uso del parámetro en el método Show(), es allí donde se especifica quien será el owner, en este caso se hace uso de this ya que el formulario donde estamos en ese momento será quien realiza la apertura.

 

Cuarto Paso – Comunicación desde el formulario hijo

En esta ultima sección se visualizara como el formulario hijo envía datos al padre.

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

    private void Button1_Click(object sender, EventArgs e)
    {
        IForm formInterface = this.Owner as IForm;

        if(formInterface != null)
            formInterface.ChangeTextBoxText(TextBox1.Text);
    }

}

En el código se puede apreciar claramente el uso de la propiedad Owner junto al this que en este caso representa al Form2.

Es interesante además remarcar la necesidad de castear la propiedad, en este caso particular se realiza mediante el uso de “as”
Es muy útil hacer uso de este ya que ante una imposibilidad o error de casteo la aplicación no producirá un error, en este caso simplemente la variable obtendrá el valor null, es por ello que se hace uso del “if” para preguntar si pudo realizar la conversión de tipos.

 

Conclusión


Bueno después de analizar el ejemplo verán como por medio de un simple interfaz se logra desacoplar las dependencias entre formulario facilitando la comunicación entre ellos, la simple definición de un contrato asegura que el formulario hijo pueda interactuar ya no solo con un forma padre único, sino con cualquier otro formulario que lo utilice e implemente la interfaz.

[C#]
[VB.NET]