Tema destacado: Grupo de acebook de elhacker.net
Autor
|
Tema: Ayuda con una propiedad tipo lista en un custom control (Leído 2,987 veces)
|
|
seba123neo
|
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 ?
|
|
|
|
|
En línea
|
Mucha gente, especialmente la ignorante desea castigarte por decir la verdad, por ser correcto, por ser tú. Nunca te disculpes por ser correcto, o por estar años delante de tu tiempo. Si estas en lo cierto, y lo sabes, que hable tu razón. Incluso si eres una minoria de uno solo, la verdad sigue siendo la verdad. M. Gandhi
|
|
|
<ИΘZIЭ(ŦB>
Desconectado
Mensajes: 109
-cyman-
|
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?
|
|
|
|
|
En línea
|
|
|
|
<ИΘZIЭ(ŦB>
Desconectado
Mensajes: 109
-cyman-
|
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?
|
|
|
|
|
En línea
|
|
|
|
|
[D4N93R]
|
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. 
|
|
|
|
|
En línea
|
|
|
|
<ИΘZIЭ(ŦB>
Desconectado
Mensajes: 109
-cyman-
|
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.
|
|
|
|
|
En línea
|
|
|
|
Novlucker
Ninja y
Ex-Staff
Desconectado
Mensajes: 10.239
Yo que tu lo pienso dos veces
|
Te lo dijo aquí 
|
|
|
|
|
En línea
|
Contribuye con la limpieza del foro, reporta los "casos perdidos" a un MOD XD http://twitter.com/novlucker "Hay dos cosas infinitas: el Universo y la estupidez humana. Y de la primera no estoy muy seguro." Albert Einstein
|
|
|
<ИΘZIЭ(ŦB>
Desconectado
Mensajes: 109
-cyman-
|
Ya lo leí hermano, pero no entendí cómo aplicarlo a mi caso. Gracias.
|
|
|
|
|
En línea
|
|
|
|
|
[D4N93R]
|
Para detectar el cambio te dije que sobreescribieras el InsertItem .. 
|
|
|
|
|
En línea
|
|
|
|
<ИΘZIЭ(ŦB>
Desconectado
Mensajes: 109
-cyman-
|
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?
|
|
|
|
|
En línea
|
|
|
|
|
[D4N93R]
|
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
|
|
|
|
|
En línea
|
|
|
|
<ИΘZIЭ(ŦB>
Desconectado
Mensajes: 109
-cyman-
|
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é?
|
|
|
|
|
En línea
|
|
|
|
|
|