Introducción
En mas de una oportunidad surgió el hecho de comunicar formulario y pasar información entre los mismos, cuando estos se invocan uno a otra la solución es relativamente simple, pero que sucede cuando las distintas invocaciones deben capturar y conservar los datos en cada paso que realizan.
Es aquí donde entra en juego un patrón bien simple de aplicar pero no por eso menos potente, hago referencia al singleton.
Para el presente artículo platearemos un escenario nada complicado, simplemente algunos forms donde se capturan datos números, pero esta información deberá ser usada en la ultima pantalla, la cual realiza el calculo con los datos recolectados en los pasos previos.
1- Singleton, Pasar datos entre formularios
Implementar el patrón es muy simple, solo se deben aplicar ciertas reglas que abrigan a tomar la misma instancia.
public class RecolectarDatos { private static RecolectarDatos datos; private RecolectarDatos() { } public static RecolectarDatos Instance() { if (datos == null) { datos = new RecolectarDatos(); } return datos; } public int Dato1 { get; set; } public int Dato2 { get; set; } public int Dato3 { get; set; } public int Dato4 { get; set; } public int Dato5 { get; set; } }
El primer punto es definir una instancia static del propia clase singleton (línea 3)
Segundo, definir el constructor de la clase como privado (línea 5), de esta forma no se podrán crear instancia de la clase, salvo desde dentro de la propia clase.
Tercero, definir un método o propiedad static, la cual será el punto central por donde se podrá recuperar una instancia de la clase (línea 9), en este punto es donde se valida y crea la instancia de la variable static definida mas arriba, es por esto que siempre se retorna esta misma instancia.
El resto del código pueden ser método, propiedades, otras instancias de clases, o sea se puede aplicar cualquier concepto de POO sin problemas, porque el patron singleton devuelve una única instancia, pero esta tiene comportamiento como cualquier otro objeto.
2 – Eventos, Informar de cambios entre formulario
Al llegar al ultimo formulario era necesario informar al primero que las operaciones se realizaron correctamente, pero entre estos formulario no hay visibilidad alguna, no se aplico ninguna pasamano de instancias entre los formularios, o algo que los comunique.
Es por eso que la subscripción a un evento genérico resulta ideal para avisar de una determinada acción sin ser necesario pasar instancias.
public static class CompleteEvents { public delegate void CompleteHandler(CompleteEventArgs args); public static event CompleteHandler Complete; public static void RaiseEvent(int calculo) { if(Complete != null) Complete(new CompleteEventArgs(calculo)); } } public class CompleteEventArgs : EventArgs { public CompleteEventArgs(int calculo) { this.Calculo = calculo; } public int Calculo { get; set; } }
El formulario principal se adjunta al evento definido en la clase, mientras que en el ultimo formulario es invocado el método RaiseEvent() que lanzara la acción.
Adicionalmente se define un argumento del evento para informar el resultado del calculo, igualmente en este caso por aplicar singleton, quizás no era necesario, ya que se podría haber tomado directamente los valores de cada dato recolectado y realizar nuevamente el calculo.
Código del ejemplo
[C#] |
[VB.NET] |
muy buen aporte leandro,lo de patrones siempre es un tema interesante, .No sabia como usar una una clase como parametro del delegado pero este ejemplo es ilustratvo, y me gusto tener el evento, el delegado y el raise event dentro de una clase estatica (en CompleteEvents )
ResponderEliminarla clase CompleteEventArgs porque hereda de EventArgs porque es para datos ?
public class CompleteEventArgs : EventArgs
Se puede hacer una clase similar , si tengo un metodo de esta forma btnATodas_Command(object sender, CommandEventArgs e)
hola
ResponderEliminarhereda de EventArgs porque esa clase se usara en la firma del evento que se define
con respecto al btnATodas_Command, este evento ya define una forma en sus parametros, porque alli usa CommandEventArgs, alli simplemente lo usas porque ya existe, el otro lo habai creado porque es un evento que se define completo, no es existente
saludos
gracias leandro. Esta muy bueno tu blog tiene notas bastantes interesantes
ResponderEliminarHEY LEANDRO como stas espero que todo marche de maravilla, yo aqui con un asunto que no me da descanzo, resulta que mis crystal en la pc de desarrollo funciona y al intalar la aplicacion en otra me pide id y passwrod como soluciono eso de una vez por todas trabajo en vb.net 2010 y sql server 2008 express ayudame porfavor estoy por cerrar mi codigo y aun no puedo por eso..gracias de antemano Leandro
ResponderEliminarhola MINDCORRUPTER
ResponderEliminarel reporte que has creado lo estas conectando directamente a la base de datos o usas un dataset tipado ?
porque si usas un dataset tipado quizas se deba a que anteriormente habias conectado el reporte pero luego cambiaste al este dataset, esto hace que crystal aun se haya quedado con los datos de la conexion por eso los solicita
valida las conexiones que puediera tener el reporte y si estas asignando de forma correcta el dataset como origen de datos
saludos
hola leandro gracias por todos tus aportes tenia una consulta:
ResponderEliminarcomo puedo hacer para un datatable usarlo en toda la aplicacion aplicando singleton no se mucho de singleton pero es lo que necesito
.... mi profesor me dijo de que no puedo crear un datatable cada vez que yo quiera por que tendria muchas copias en memoria y me aconsejo usar singleton me podrias ayudar estaria en deuda contigo
hola francisco
ResponderEliminarpor lo del consumo de memoria depende, si creas el datatable en el ambito correcto dodne lo usas no deberia ahber problema, o sea si creas datatable a nivel del formulario y haces esto en varios de seguro esto consumira memoria teniendo replcias de los mismos datos
pero si los creas solo en el metodo dodne lo usas y solo alli, eso no genera consumo de memoria, todo esta en definir el ambito en que lo creras, siempre deberia ser el menor posible
podrias usar este concepto si se trata de info global que suaras en varios lados, la tecnica es la misma dentro del singleton define una variable con el datatable
aunque la verdad recomendaria que no uses datatable porque no defines una List<> de una clase con propiedades
saludos
es que el datatable que ocupare lo necesitan varias clases para comparar datos.... gracias ya pude resolverlo con singleton..
ResponderEliminarsi me ayudaras con otra duda...
tengo una aplicacion web de productos de la BD northwind
dos campos
idproducto
cantidad
simplemente los lleno y eso llama a una funcion llamada
realizarventa(idproducto,cantidad)
esta realiza la coneccion y el command y todo el rollo para guardar ..... tengo otra aplicacion de escritorio que pide lo mismo
idproducto
cantidad
para guardar eso llamo al servico web y a la funcion realizarventa(idproducto,cantidad)
y le paso los campos
y tengo un datagrid donde tengo toda la tabla products
la pregunta es... como puedo hacer para que si hago una venta en la aplicacion web se actualizen los datos del datagrid teniendo la aplicacion abierta claro
perdon si no le entiendes a lo que escribo de antemano gracias
hola francisco
ResponderEliminarvas a tener que investigar sobre SignalR
http://social.msdn.microsoft.com/Forums/es-ES/netfxwebes/thread/11e35154-cea7-41d4-b414-813e5e52d2dd
este permite desde el server notificar a los clientes para que actualicen
eso si necesitas .net 4 para que funcione
saludos
Me recomiendas usar un object pooling de datatables para mi aplicacion implementando singleton???
ResponderEliminargracias.
hola francisco
ResponderEliminarhasta donde se no existe ningun pooling en los datatable, existe ese concepto en ado.net para administrar las conexiones a la db, pero esto no tene nada que ver con singletos o el objetivo que aqui se plantea en la comunicacion de formularios
saludos
hola d nuevo. primero que nada debo felicitarte por cada una de tus entradas que son excelentes, quisiera pedirte ayuda pues tengo un form padre y varios hijos a los que accedo por medio de un treeview y un panel y los form hijos se muestran en dicho panel contenido en el form padre, el problema que tengo es que solo tengo un botón de guardar nada mas y esta localizado en el padre pero no se como guardar los datos introducidos en las cajas de texto de los form hijos en el padre.
ResponderEliminarhola
ResponderEliminarpodrias desde el form padre enviar una accion al forma hijo
si defines una interfaz que especifique el nombre, podrias invocar cualqueir accion en el form hijo, siempre y cuando tengas la instancia del mismo
podrias aplicar una logica como esta
[WinForms] Realizar Acciones en formularios hijo
saludos
Hola Leandro esta muy educativo tu ejemplo gracias, pero si yo quiero usar string no me funciona el tryparse cual debo usar?. Gracias
ResponderEliminarhola Richard
ResponderEliminarno entendi, que es lo que intentas parsear ?
saludos
ok te explico veo que la mayoria te ha consultado como obtener y guardar la informacion adicional del usuario logueado, bueno yo estoy desarrollando en capas (basado en tus ejemplos) y todo funciona bien, no se como lo siguiente: quiero hacer un query(store procedure) con inner join para tener el usuario, password, codEmpleado, NombreEmpleado. Pero como estoy usando entidades no se como hacerlo esto en mi capa de acceso, y despues guardar la informacion en la Clase ObtenerDatos() ya que tu ejemplo de siglenton() usas integer y yo tengo tipo string y el tryparse me da error con strig
ResponderEliminarhola Richard
ResponderEliminaren tu capa de datos podrias hacer como explico aqui
[WinForms] Edición Empleados
para cargar una entidad
saludos
Hola Leandro disculpa necesito tu ayuda, sigo intentando guardar en mi clas RecolectarDatos.vb pero no lo condigo. En dicha clase tengo 3 datos de los cuales 1 es string, bien en mi formulario Login tengo esto: a nivel de formulario private usuario as usuariosEntity = Nothing
ResponderEliminarprivate Intentos as integer = 0
en el boton iniciar:
'
usuario = UsuarioBOL.GetByUsuariosId(TxtUsuario.Text)
Dim codrol As Integer = Convert.ToInt32(usuario.cod_rol)
Dim codempleado As Integer = Convert.ToInt32(usuario.cod_empleado)
Dim users As String = usuario.cod_usuario
Dim datos As RecolectarDatos = RecolectarDatos.Instance()
Dim temp As Integer = 0
I If StrConv(users, temp) Then
datos.Dato1 = temp
End If
If Integer.TryParse(codrol, temp) Then
datos.Dato2 = temp
End If
If Integer.TryParse(codempleado, temp) Then
datos.Dato3 = temp
End If
Pero me sale un error: La conversion de la cadena "admin" en el tipo Boolean no es valida.
No se que hacer
hola
ResponderEliminarestas seguro que en cod_rol devuelves un valor numerico en lugar de la descripcion "admin" ?
si pones un breakpoint en el codigo y pasas el mouse por sobre las propiedades para evaluar que contenido presentan cuando conviertes en int asignas un valor numerico
saludos
ya lo revise y es un string aqui esta el codigo en la capa de acceso:
ResponderEliminarPublic Shared Function GetUsuarioById(CodUsuario As String) As Usuarios
Dim usuario As Usuarios = Nothing
Using conn As New SqlConnection(ConfigurationManager.ConnectionStrings("default").ToString())
conn.Open()
Dim cmd As New SqlCommand("SP_Listar_Usuarios", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@criterio", CodUsuario)
Dim reader As SqlDataReader = cmd.ExecuteReader()
If reader.Read() Then
usuario = LoadComboUsuarios(reader, True)
End If
End Using
Return usuario
End Function
hola Richard
ResponderEliminarsi es un string ahi esta le problema no debe serlo, debes asegurarte que el campo devuelve un valor numerico
si es texto alfanumerico este no se puede convertir a bool, el campo deberia ser del tipo "bit" en la base de datos
saludos
Sos groso, sabelo!
ResponderEliminar¿Cómo pasar un valor de un WinForm a una página HTM?
ResponderEliminarHola, necesito pasar el texto de un Textbox de un formulario windows a un textbox de una página HTM dentro de mi proyecto... cómo lo hago por favor?
Muchas gracias,
Paris
hola Paris
ResponderEliminarpero la pagina html la cargas donde ?
si usas un control WebBrowser dentro del form podrias navegasd la pagina y luego mediante la funcionalidad del control acceder al html he interactuar con el mismo
pero no se si es que haces esto o como seria el contexto del problema
saludos
Yo seteo las variable en el segundo formulario , luego cierro con close, pero el primer formulario esta abierto, en que momento le asigno el valor, osea en que evento del primer formulario utilizo las variables.
ResponderEliminarhola Luis
ResponderEliminares que si cierras el form sin nada mas es logico que no suceda nada
debes informar al form1 que el otro form se cerro
para esto usas eventos, si el form1 es quien lanza el form2 podrias usar el evento Closing para detectar el cierre
o sea desde el form1 usarias
Form2 frm2 = new Form2();
frm2.FormClosing += from2_Formclosing;
frm2.Show();
de esta forma definiendo el evento desde el form1 puede controlar el cierre
saludos
Hola excelente post, solo me queda una duda, en la parte de
ResponderEliminarpublic int Dato1 { get; set; }
obvimanete adquiere el valor que se se escribió en el form, pero qué pasaría si hay un form extra donde necesita que las variables no valgan nada ?
¿cómo se haría un método universal que limpie todas las variables ?
En tu ejemplo nada mas son pocas, pero si fueran muchísimas?
Gracias por la respuesta, saludos
Hola gracias por el ejemplo pero tengo una duda me podrías ayudar, por ejemplo:
ResponderEliminardoy clic en comenzar e ingreso los 3 primeros dígitos y confirmo.
en la siguiente pantalla ingreso los 2 números restantes.
pero si doy clic en comenzar de nuevo e ingreso los 3 números se sobrescriben los que ya avía puesto hay alguna manera de que esto no suceda para iniciar varias veces la aplicación y realizar distintas operaciones sin que los datos se sobrescriban.
Gracias de antemano
hola kymcha
ResponderEliminarpodrias utilizar una base de datos o quizas tener una lista que serialices a xml para poder ir agregando registros o items para ir conservandolos y que no se pisen con los nuevos
si solo mantienes un unico item es logico que solo podras pisar ese, pero si vas agregando sobre una lista podrias trabajar con la misma en caso de querer acceder a la historia de datos ingresados
saludos
Super como siempre Leadro, muchas gracias por la aportación
ResponderEliminarHola,
ResponderEliminarSolo tengo una frase que decir, "GRACIAS TOTALES LEANDRO". Me sacaste de un lió en el que llevaba mas de 2 semanas.
Saludos.
Hola Leandro,
ResponderEliminarNo he entendido bien tu ejemplo de Singleton, pero aún así me gustaría tener el código fuente para poderlo revisar, ...lo podrías compartir por favor, ya que los links, actualmente están caídos.
Muchas gracias.