viernes, 20 de noviembre de 2009

Aplicación Pomodoro en C# Mobile 6.5 – Delegados o como avisar a un formulario padre que ha ocurrido algo en un formulario hijo.

Enunciado:
  • Tengo un formulario A que llama a un formulario B.
  • Tengo una tabla de tareas en el formulario B y puedo añadir, modificar o borrar.
  • Tengo una lista desplegable de tareas en el formulario A y quiero que se actualice cuando en el formulario B modifique la tabla de tareas.

Para ello vamos a utilizar Delegados y Eventos que, de forma muy sencilla y muy potente, me permite una comunicación discreta -es decir sin necesidad de ser pública - entre ambos formularios.

Primero nos vamos al formulario B y declaramos el delegado: 

     public delegate void cambioEnListaDeTareasDelegate();

Despúes vamos a declarar el CallBack, es decir la variable que va a recibir la llamada del delegado en el formulario A.

     public cambioEnListaDeTareasDelegate cambioEnListaDeToDoCallback;

Despúes nos iremos al punto en donde decidamos que conviene situar el "aviso" de que hemos realizado un cambio en la tabla de tareas (seguimos en el formulario B). Por ejémplo en el método de guardarTarea();

      private void guardarTarea()
          {
                // Realizo las operaciones de guardar los datos.


                // Aquí lanzo la alerta al formulario A (o cualquier otro que este suscrito)

               cambioEnListaDeDatosCallback();
           }

Ya hemos acabado en el formulario B, consiguiendo que cada vez que se guarden los datos avise a todo aquel que esté suscrito que ha habido un cambio en la tabla de tareas.

Ahora nos vamos al formulario A y en el momento en que voy a abrir al formulario B le digo que, además, voy a hacer algo cada vez que en el formulario B se cambie la tabla de tareas.

¿Dónde le digo todo esto?, pues en este ejemplo en el evento click del botón de navegación que abre el formulario B. Pero podría ser en cualquier otro sitio siempre que hayamos instanciado el formulario B.

     private void bAdelante_Click(object sender, EventArgs e)
     {
            formularioB paginaSiguiente = new formularioB();
 
           // El truco del almendruco que enlaza la acción al evento.
           paginaSiguiente.cambioEnListaDeTareasCallback = new formularioB.cambioEnListaDeTareasDelegate(refrescaCombo);

            paginaSiguiente.ShowDialog();
     }

Como veís es una navegación entre formularios típica en WinForms, instanciando el formulario B y diciendole que lo muestre con show(). La diferencia, y el truco, es que llamamos a la campo de CallBack de la instancia del formulario B que queremos mostrar y le asignamos el delegado de la clase formularioB diciendole, además, entre paréntesis el qué quiere que haga. En este caso lanzar el método que refresca la lista despegable de tareas.

Finalmente he conseguido lo que quiero. Estoy en el formulario A, abro el formulario B y cambio la Tabla de tareas y automáticamente en el formulario A se me refresca la lista desplegable para actualizarla con los cambios realizados en el formulario B.

P.D. Es obvio que debes persistir de alguna forma la tabla de tareas para que ambos formularios utilicen el mismo juego de datos.

Fuente: C# corner: Muhammad Mosa - "Using delegates to communication between windows forms"
(No os preocupeis por la pantalla de identificación, se redirige automáticamente al artículo.)

miércoles, 11 de noviembre de 2009

Aplicación Pomodoro en C# Mobile 6.5 – Copiar una selección de filas de un DataTable en otro DataTable

El desarrollo de software muchas veces es como un perro al sentarse. Damos vueltas y vueltas hasta que encontramos el lado que más nos parece el bueno.

Enunciado: Quiero leer un DataTable, seleccionar un conjunto de filas y devolverlo a la función que me ha invocado.

Primera aproximación. Obtengo una colección de filas con un .select() y las .add en un nuevo DataTable. MECK!! Error, eso no se puede hacer sin liarte con clonaciones y demás gaitas.

Segunda aproximación. Obtengo un DataView del DataTable filtrado en la instanciación por medio del rowFilter. MECK!! Me obliga a cambiar todo el código que utilice este método y que espere un DataTable.

Aproximación y resolución:

///
/// Devuelve el DataTable filtrado obtenido de la fuente de datos.
///
///
public DataTable leeTablaFiltrada()
{
DataTable tabla = new DataTable();
tabla = leeTabla(); // Función que recupera el DataTable de la fuente de datos.

DataView vista = new DataView(tabla, "tabla de filtro = 'valor de filtro' ", "tabla de ordenamiento DESC", DataViewRowState.CurrentRows);
// Tener cuidado de si la condicion de filtro es un string ponerlo entre comillas simples

return vista.ToTable(); // Este es el "milagro"
}

Moola!!

martes, 10 de noviembre de 2009

Aplicación Pomodoro en C# Mobile 6.5 – selección de una misma fila en un DataGrid

Continuamos con la "pequeñas" diferencias al codificar para un control DataGrid para SmartPhone que hacen perder tanto tiempo.

El problema aparece cuando utilizamos el evento DataGrid_CurrentCellChanged para localizar el registro seleccionado en el DataGrid y abrir el formulario de edición con todos sus datos cargados.

Cuando hemos realizado los cambios y hemos vuelto a la vista del DataGrid, me encontré que no podía volver a editar la misma fila porque el evento solamente salta cuando se cambia de celda seleccionada.

Despúes de varios intentos con .select() y .CurrentRowIndex, con resultados nulos o erroneos, le dí una vuelta a los eventos que se actualizan por medio de la hoja de propiedades del control DataGrid desde el lado visual del Visual Studio (no me gusta esta forma pero es la más cómoda y menos intuitiva).

Aquí lo que hice fue decirle que en el evento Click del DataGrid, utilizará el mismo método suscritor que el que captura el CurrentCellChanged... y voala!! Todo funciona OK.

viernes, 6 de noviembre de 2009

GridViewRowEventArgs diferencias en VB.net y C#

Mientras intento recuperar mi código del cronómetro Pomodoro, estoy adelantando un pequeño calendario para la página de mi club de Tiro con Arco.

Y recuperando un código antigüo que me mejora la interacción con el objeto GridView realizado en Visual Basic.NET, he visto que hay pequeñas y molestas diferencias sintácticas entre ambos lenguajes:

VB:
ClientScript.GetPostBackEventReference(sender, "$" & CType(e.Row.FindControl(""), Label).Text)

C#:
ClientScript.GetPostBackEventReference(((Control)sender), "$" + ((Label) e.Row.FindControl("")).Text));

Cosas a reseñar en C#.
1. El sender se debe convertir al tipo Control genérico. No es necesario específicar el tipo de control.
2. La traducción de la conversión desde VB CType(control, tipoDeControl) a C# es: ((tipoDeControl) control))

Que sea de ayuda.