Qué tal compañeros de foro! Hace tiempo que no pasaba por aqui. Saludos...
Les cuento que hace unos meses aprendi a crear mis propios controles personalizados (custom control), y si que ha sido provechoso. Es la mejor solucion cuando se quiere modificar o agregar propiedades a un control predefinido, o bien crear uno totalmente a la medida.
Pues bien, esto ultimo es justamente mi caso. Estoy creando un panel de botones, al que pueda ir cargandole items tal como se hace en un ListView, por ejemplo, solo que en este caso los items seran botones, que por cierto también son creados por mi.
En fin, para ello me cree una propiedad tipo lista (List (Of CrystalButton)), que se supone usaré para cargar los botones al panel. Pues bien, es justo ahi donde tengo el problema, pues no sé como asociar la inclusion de items a algun evento. ¿Para qué quiero eso? Pues porque es justo ahi donde debo incluir el codigo que me agregue el nuevo item al control e indique su posicion. De no hacer eso sólo puedo cargar ítems en la propiedad tipo lista, pero los botones no se agregan a mi control.
¿Me echan la mano?
Ah! Olvidé mencionar que uso el Visual Studio 2008, y estoy programando en Visual Basic.
Bueno, lo primero que se me ocurre es que crees tu propio customlist heredando de list<t> y sobrecargues el método add agregando un evento :D
Saludos
No entiendo muy bien como lo tienes hecho, por lo que yo he entendido, has heredado tu control de un Listview verdad??
Si es asi, prueba a suscribirte al evento "ItemInserted".
Si eso no te funciona pon el codigo de tu control y asi podre intentar ayudarte mas ;)
Un saludo
Lo que entiendo es que tiene un panel en el que uno de sus atributos es una lista generica de botones, y quiere que al agregar un botón en esa lista, se dispare un evento que lo ubique en el panel :P
Puede que yo haya entendido mal :xD
Saludos
Cita de: Novlucker en 10 Marzo 2011, 19:24 PM
Lo que entiendo es que tiene un panel en el que uno de sus atributos es una lista generica de botones, y quiere que al agregar un botón en esa lista, se dispare un evento que lo ubique en el panel :P
Puede que yo haya entendido mal :xD
Saludos
Tienes razon Novluker, se refiere a un panel xDD yo lei listview y claro, ya me lie pensando en eso jajaja
Otra cosa que se peude intentar es que en vez de agregar los botones como items de un list, que se agregen a la coleccion de controles del panel y se suscriba al evento "ControlAdded" praa saber cuando se ha añadido un boton a la lista de controles del panel.
Bien. Veo que ya entienden lo que quiero, y me han "sugerido" qué hacer. El asunto es que de verdad no tengo idea de cómo hacer lo que dicen. Por ejemplo, ¿cómo 'suscribo' la adición de botones a ese evento "ControAdded"? De verdad es primera vez que intento hacer un control de ese tipo, así que necesito detalles.
Otra cosa: mi control no es un Panel; es decir, no hereda del control Panel. Simplemente funcionará cómo un panel porque contendrá una serie de botones que el usuario irá cargando.
Para que podamos ayudarte mejor lo suyo seria que pudieses el codigo de tu control.
Sino hereda de un panel del que peudas coger eventos tipo ControlAdded puedes crearte tu propio evento y hacer que este salte cuando agregues un nuevo elemento a la lista.
pero es que sin ver tu codigo no se me ocurre mucho mas que decirte para ayudarte.
un saludo
Entiendo. El asunto es que no tengo código alguno todavía. Lo único que hice fue agregar un nuevo UserControl al proyecto. Cómo saben, esto me muestra un cuadro vacío en la ventana de diseño. Luego me fui al código y agregué una nueva propiedad tipo lista (como ya mencioné), y fue entonces cuando noté que no sabía que más hacer.
Así pues, hasta ahora sólo tengo esta propiedad llamada Items, a la que puedo agregar elementos sin problema desde el modo diseño. Sólo me hace falta captar la inclusión de los ítems en la propiedad, para agregarlos al UserControl.
Hola,
Es un poco largo, pero es la manera más sexy de y elegante de hacerlo:
1) En vez de utilizar List(Of CrystalControl), crea una clase que herede de Collection(Of T).
2) En esa clase que la llamaría CrystalControlCollection, tienes que crear un evento público (algo como ControlAdded) con un EventHandler(Of CrystalControlEventArgs).
3)CrystalControlEventArgs es otra clase que hereda de EventArgs con una propiedad pública de tipo CrystalControl que se llame Item (u otro nombre que quieras)
4) Luego haces override del método InsertItem en la clase CrystalControlCollection y ahi llamas al evento ControlAdded (con RaiseEvent en vb.net) en donde le pasas el control que se está añadiendo.
5) Sustituyes la lista por CrystalControlCollection, y te suscribes al evento ControlAdded :)
Puedes hacer muchas más cosas como cuando sacas un control de la lista llamar a otro evento en donde realmente sacas el control del UI. Esto se llama event driven development , creo.
Un saludo!
Que pesado! es como en el code del bot irc que saltaba por todas las páginas buscando eventos :xD
Es parecido a lo que puse al principio :xD la diferencia esta en que había obviado el tema de que los métodos de list no se pueden sobreescribir (por eso la sobrecarga), y lo del customeventhandler. ¿Podemos dar por buena mi respuesta? Di que si, di que si :D
Y pasate más por el foro, que sino sigo sugiriendo chapuzas :xD
Saludos
Claro que esta bien tu respuesta xD Ahora es que la leo! Es que hoy llegué cansado y solo leí el primer post y respondí. Ahora es que leí todo completo :P
Y si, el bot está programado en event driven.
:xD
Además me paso todos los días por el foro :¬¬
Bien. Agradezco de verdad toda la explicación, aunque un poco compleja para mí. Igual hice todo lo que enumeró, excepto por el más importante, el de suscribirse al evento ControlAdded, que es justo lo que me hace falta saber. ¿Será posible que escriban un ejemplo del código que suscribe un evento de mi UserControl al evento ControlAdded de la clase CrystalControlCollection? Por favor...
Atencion: Puede que lo que diga sea disparate pero acabo de quemarme el cerebro con un algoritmo.
Y si inventas tu propia funcion AgregarBoton y ahi lo ubicas? O haz que primero agregue los botones y en una funcion "UbicarBotones" haces lo que tengas que hacer para mostrarlos :P
Seria mas facil que crear una copia personalizada de List(Of t) o similar :P
@<ИΘZIЭ(ŦB>
Te recomiendo que te leas esto:
http://carlossantos.wordpress.com/2008/01/20/events-delegates/
http://foro.elhacker.net/net/tutorial_delegados_en_net_c-t301022.0.html (para C# pero es básicamente lo mismo)
@Raul: >_> eso es un poco caimán.
#DEFINE CAIMAN "Ordinario"
xD
haber si me queda claro lo que queres hacer, simplemente es un usercontrol que crea botones ? o sea yo le digo que me cree 10 botones y el usercontrol muestra eso ? y que cada uno tenga su evento no ?
Veo que aún hay algunas dudas. Intentaré explicar todo de nuevo.
Decidí crear un control (UserControl) que funcione como un contenedor de Botones. Sé bien que eso puedo hacerlo con un Panel normal, agregandole Botones desde la ToolBox, pero no quiero hacerlo así. Quiero hacerlo en mi propio control desde una propiedad tipo lista o colección llamada Items. En modo diseño, dicha propiedad me muestra la palabra "(Collection)" seguida de un pequeño botón con tres puntitos que al oprimirse me muestra mi colección de botones en una ventana, con un botón Add y otro Remove. Con Add voy cargando botones a la colección y asignándole sus respectivas propiedades a cada uno. Una vez terminada la inclusión, oprimo el botón Ok de la ventana, quedando lista la colección de botones. Si vuelvo a oprimir el botón con tres puntitos veo la colección ya creada. Hasta ahí voy perfecto.
Ahora bien, lo que me hace falta es que al oprimir el botón Ok en la ventana de la colección se me carguen los botones al UserControl. Necesito captar el cambio en la colección para llamar al código que me agrega y ordena los botones en el UserControl. ¿Cómo lo hago?
Les cuento que he estado dándome duro con mi control a fin de hallar la respuesta a mi incógnita, y se podría decir que he tenido éxito. No obstante, hay detalles que aún me gustaría aclarar.
Respecto a la pregunta anterior, ya noté cuándo detectar el cambio de la propiedad tipo colección, aunque me pareció muy raro. Al principio, cuando la creé, supuse que dicho cambio ocurriría en el bloque Set de la propiedad, pero le puse un Breakpoint y no pasaba nada; es decir que la inclusión de un nuevo botón en la colección no estaba relacionado con Set. Por eso estaba preguntando cómo podía detectarla.
Sin embargo, posteriormente noté (usando otro Breakpoint) que al agregar o remover un ítem de la colección se ejecutaba el bloque Get de la propiedad; no entendí por qué. Pero igual escribí allí el llamado al método que agrega y ordena los botones en mi control.
No obstante, mis problemas no acabaron allí. Por un lado, vi que una vez incluidos los botones en mi control podía manipularlos; o sea, moverlos y de hecho sacarlos del control. Eso no me gustó. Y por otro lado, empecé a tener un error con algo llamado SerializableAtribute. Eso me condujo a esta página (entre otras) que me sirvió de mucho: http://msdn.microsoft.com/es-es/library/ms171731.aspx. Gracias a ese ejemplo descubrí que ese extraño caso de que al cambiar la colección se ejecutara Get en vez de Set ocurre sólo al definir la propiedad como lista o colección; pero al definirla como Array se corrige la eventualidad. Es decir que ahora que tengo la propiedad tipo Array, se ejecuta Set al cambiar la colección y presionar el botón Ok en el editor de colecciones. No obstante, sigo sin entender por qué con List y Collection no. Si alguien lo sabe...
Y lo otro que quiero saber es cómo puedo cargar los botones a mi control sin que puedan manipularse. Quiero que sean como los que uno crea directamente en un UserControl, que no son manipulables desde donde usa el mismo. ¿Alguna idea?
Citar
Respecto a la pregunta anterior, ya noté cuándo detectar el cambio de la propiedad tipo colección, aunque me pareció muy raro. Al principio, cuando la creé, supuse que dicho cambio ocurriría en el bloque Set de la propiedad, pero le puse un Breakpoint y no pasaba nada; es decir que la inclusión de un nuevo botón en la colección no estaba relacionado con Set. Por eso estaba preguntando cómo podía detectarla.
Correcto, no va a pasar nada porque estás cambiando valores del List no estas cambiando el List como tal.
En el bloque get se detiene no porque estas cambiando la coleccion sino porque pides la colección para agregar, eliminar, o lo que sea hacia el objecto como tal. Pudo haber sido cualquier otra clase, no necesariamente una lista y obtendrías el mismo comportamiento.
Tu puedes hacerlo como quieras, pero la manera que te habíamos dicho es la más sexy.
Un saludo. :)
Claro hermano. De hecho, hice todo lo que sugeriste, pero no me dijiste cómo detectar el cambio de la colección. Nunca supe cómo implementar el evento de la colección en el UserControl. Por eso busqué otras fuentes.
Te lo dijo aquí :rolleyes:
Cita de: [D4N93R] en 11 Marzo 2011, 19:55 PM
@<ИΘZIЭ(ŦB>
Te recomiendo que te leas esto:
http://carlossantos.wordpress.com/2008/01/20/events-delegates/
http://foro.elhacker.net/net/tutorial_delegados_en_net_c-t301022.0.html (para C# pero es básicamente lo mismo)
Ya lo leí hermano, pero no entendí cómo aplicarlo a mi caso. Gracias.
Para detectar el cambio te dije que sobreescribieras el InsertItem .. :)
Sigo insistiendo aquí porque todavía tengo algunos problemas con la propiedad tipo colección.
Antes que nada, debo decir que ya pude detectar el cambio en la colección. En efecto, había que lanzar el evento público ControlAdded desde el evento InsertItem sobreescrito de la colección, y luego suscribirse al mismo desde el UserControl contenedor, cómo sugirieron. Ahora bien, ¿cómo se hace la suscripción? Estuve esperando esa respuesta todo el tiempo, más nunca me llegó; apenas vine a saberlo hace unos minutos.
Resulta que lo único que había que hacer era agregar WithEvents a la declaración de la variable que complementa a la propiedad colección, y luego agregar Handles variable.ControlAdded al método que incluye y ordena los botones.
Ahora bien, como mencioné antes, mis problemas no han terminado, así que requiero de su pericia nuevamente.
Resulta que, por alguna extraña razón que desconozco, el evento RemoveItem no se ejecuta al remover un ítem de la colección. De verdad no lo entiendo. Hice lo mismo que con InsertItem y nada que me da resultado, pues noté que la compilación no entra en el bloque RemoveItem cuando remuevo un ítem de la colección. ¿Por qué pasa eso?
Eso no debería pasar. Podrías postear el codigo del Collection.
Un saludo!
PD: Encontré esto en MSDN:
Imports System
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Public Class Dinosaurs
Inherits Collection(Of String)
Public Event Changed As EventHandler(Of DinosaursChangedEventArgs)
Protected Overrides Sub InsertItem( _
ByVal index As Integer, ByVal newItem As String)
MyBase.InsertItem(index, newItem)
RaiseEvent Changed(Me, New DinosaursChangedEventArgs( _
ChangeType.Added, newItem, Nothing))
End Sub
Protected Overrides Sub SetItem(ByVal index As Integer, _
ByVal newItem As String)
Dim replaced As String = Items(index)
MyBase.SetItem(index, newItem)
RaiseEvent Changed(Me, New DinosaursChangedEventArgs( _
ChangeType.Replaced, replaced, newItem))
End Sub
Protected Overrides Sub RemoveItem(ByVal index As Integer)
Dim removedItem As String = Items(index)
MyBase.RemoveItem(index)
RaiseEvent Changed(Me, New DinosaursChangedEventArgs( _
ChangeType.Removed, removedItem, Nothing))
End Sub
Protected Overrides Sub ClearItems()
MyBase.ClearItems()
RaiseEvent Changed(Me, New DinosaursChangedEventArgs( _
ChangeType.Cleared, Nothing, Nothing))
End Sub
End Class
' Event argument for the Changed event.
'
Public Class DinosaursChangedEventArgs
Inherits EventArgs
Public ReadOnly ChangedItem As String
Public ReadOnly ChangeType As ChangeType
Public ReadOnly ReplacedWith As String
Public Sub New(ByVal change As ChangeType, ByVal item As String, _
ByVal replacement As String)
ChangeType = change
ChangedItem = item
ReplacedWith = replacement
End Sub
End Class
Public Enum ChangeType
Added
Removed
Replaced
Cleared
End Enum
Public Class Demo
Public Shared Sub Main()
Dim dinosaurs As New Dinosaurs
AddHandler dinosaurs.Changed, AddressOf ChangedHandler
dinosaurs.Add("Psitticosaurus")
dinosaurs.Add("Caudipteryx")
dinosaurs.Add("Compsognathus")
dinosaurs.Add("Muttaburrasaurus")
Display(dinosaurs)
Console.WriteLine(vbLf & "IndexOf(""Muttaburrasaurus""): {0}", _
dinosaurs.IndexOf("Muttaburrasaurus"))
Console.WriteLine(vbLf & "Contains(""Caudipteryx""): {0}", _
dinosaurs.Contains("Caudipteryx"))
Console.WriteLine(vbLf & "Insert(2, ""Nanotyrannus"")")
dinosaurs.Insert(2, "Nanotyrannus")
Console.WriteLine(vbLf & "dinosaurs(2): {0}", dinosaurs(2))
Console.WriteLine(vbLf & "dinosaurs(2) = ""Microraptor""")
dinosaurs(2) = "Microraptor"
Console.WriteLine(vbLf & "Remove(""Microraptor"")")
dinosaurs.Remove("Microraptor")
Console.WriteLine(vbLf & "RemoveAt(0)")
dinosaurs.RemoveAt(0)
Display(dinosaurs)
End Sub
Private Shared Sub Display(ByVal cs As Collection(Of String))
Console.WriteLine()
For Each item As String In cs
Console.WriteLine(item)
Next item
End Sub
Private Shared Sub ChangedHandler(ByVal source As Object, _
ByVal e As DinosaursChangedEventArgs)
If e.ChangeType = ChangeType.Replaced Then
Console.WriteLine("{0} was replaced with {1}", _
e.ChangedItem, e.ReplacedWith)
ElseIf e.ChangeType = ChangeType.Cleared Then
Console.WriteLine("The dinosaur list was cleared.")
Else
Console.WriteLine("{0} was {1}.", _
e.ChangedItem, e.ChangeType)
End If
End Sub
End Class
' This code example produces the following output:
'
'Psitticosaurus was Added.
'Caudipteryx was Added.
'Compsognathus was Added.
'Muttaburrasaurus was Added.
'
'Psitticosaurus
'Caudipteryx
'Compsognathus
'Muttaburrasaurus
'
'IndexOf("Muttaburrasaurus"): 3
'
'Contains("Caudipteryx"): True
'
'Insert(2, "Nanotyrannus")
'Nanotyrannus was Added.
'
'dinosaurs(2): Nanotyrannus
'
'dinosaurs(2) = "Microraptor"
'Nanotyrannus was replaced with Microraptor
'
'Remove("Microraptor")
'Microraptor was Removed.
'
'RemoveAt(0)
'Psitticosaurus was Removed.
'
'Caudipteryx
'Compsognathus
'Muttaburrasaurus
Bueno, después de tanto revisar y probar noté que el problema con Remove solo se presenta en modo de diseño. Es decir, cuando agrego mi control a un formulario y accedo a la colección a través de la propiedad, y le quito items, pues no se ejecuta el Remove de la colacción; pero si pongo un botón en el formulario para remover un item, ejecuto la aplicación y oprimo el botón, ahí sí se ejecuta el bloque Remove. No sé por qué pero así ocurre. Lo extraño es que en modo diseño sí se ejecuta el bloque Add. ¿Alguna idea de por qué?