Principiante con eventos en Visual Basic .NET

Iniciado por novalida, 23 Febrero 2013, 10:48 AM

0 Miembros y 1 Visitante están viendo este tema.

novalida

Muy buenas!!!

antes de nada quería decir que tengo poquita experiencia y estoy aprendiendo, por lo que si la respuesta es algo básico perdonad mi "ignorancia" y os pido un poco de paciencia.

Os expongo a continuación lo que me gustaría conseguir no sé si de la mejor manera, o por lo menos la más elegante, con eventos.

Tengo las siguientes clases:



    Public Class Principal
        Public objeto1 As ClaseIncluida1
        Public objeto2 As ClaseIncluida2
        Public total As Integer
    End Class

    Public Class ClaseIncluida1
        Public atributoC11 As Integer
        Public atributoC12 As Integer
    End Class

    Public Class ClaseIncluida2
        Public atributoC21 As Integer
        Public atributoC22 As Integer
    End Class



Me gustaría definir el comportamiento de la clase Principal para que cada vez que se asignase un valor a ClaseIncluida1.atributoC11 se actualizase con el mismo valor ClaseIncluida2.atributoC21 y a continuación se actualizase el valor de Principal.total con el valor de la suma de los atributos de las clases que contiene.

Sé que hay soluciones fáciles pero me gustaría que la clase Principal hiciera todo eso de forma automática, por lo que mi sentido común me dice que es lo que hace un evento.

He leido sobre el patrón observador y que en .NET se implementa mediante el uso de eventos y delegados. Conozco y entiendo esos conceptos y los he utilizado en otras ocasiones, pero no sé utilizarlos en este caso que he planteado.

He pensado que quizás el uso de eventos no sería una solución viable.

Si alguien pudiera darme alguna directriz para poder solucionar el problema se lo agradecería mucho :)

ABDERRAMAH

Puesto que dices que estas aprendiendo intentaré ser muy descriptivo:

Yo creo que más que un evento lo que necesitas usar es una propiedad. Una propiedad se usa para modificar y leer el valor de un componente de una clase a través de un interface similar a una lectura o escritura normal. Es decir, si tienes un valor string llamado var1 dentro de clase1 puedes dejarlo como privado (invisible desde fuera) y definir la propiedad var1, crearás el procedimiento set() y la función get() que se corresponden a lo ejecutado cuando se quiere leer o escribir el valor de la propiedad, y ahí puedes introducir todo el código adicional que necesites, si quieres lanzas un evento o modificas el valor directamente. Al principio parecerá algo complicado, pero verás que es una idea muy sencilla, te pongo un ejemplo.

Vamos a crear una clase con un sólo hijo de tipo integer, es la que llevará la propiedad:
* definimos el hijo como miembro privado para ocultarlo (puesto que accederemos a través de la propiedad)

Public Class testclass1
    Private my_number As Integer = 0

End Class



Y ahora queremos definir el cómo se lee o escribe my_number así que definimos la propiedad:
* get() y set() deben de tener siempre el mismo nombre, si usas ms visual studio verás que el ide lo escribe automático en cuanto pones get, así que no te preocupes.
* la propiedad tiene tipo así que en este caso usaremos el mismo del valor que queremos modificar, osea integer.

Public Class testclass1
    Private my_number As Integer = 0

    Public Property number As Integer
        Get
            '// aquí va el código que se ejecutará al leer,
            '// es como una función, necesita return
        End Get
        Set(ByVal value As Integer)
            '// aquí va el código que se ejecutará al escribir
            '// es donde quieres ejecutar el código adicional
        End Set
    End Property
End Class


Bien, ahora vamos a hacer que al leer tan sólo se devuelva el valor de my_number y al escribir lo haga y además lance un evento llamado need_update y que devuelva el valor.
Nos queda así:
Public Class testclass1
    Private my_number As Integer = 0

    ' Defino el evento de testclass1, recuerda que al crear la instancia debes hacerlo usando "withevents"
    Public Event need_update(ByVal valor_actualizado As Integer)

    Public Property number As Integer
        Get
            Return Me.my_number
        End Get
        Set(ByVal value As Integer)
            Me.my_number = value
            RaiseEvent need_update(my_number)
        End Set
    End Property
End Class


Recuerda que cuando creas el objeto debes hacerlo así, usando withevents puesto que este objeto contiene un evento que queremos usar:

Citarpublic withevents nuevotest as new testclass1

A mi personalmente me gusta más no usar eventos puesto que si windows está muy ocupado con muchas tareas va apilando los eventos en una cola y se ejecutan a trompicones. Puedes, si tienes bien localizado el objeto a modificar hacer automáticamente la modificación, es decir, si queremos modificar una clase igual que tu ClaseIncluida2 que se llama "Incluida" y pertenece a form1:


Public Class testclass1
    Private my_number As Integer = 0

    Public Property number As Integer
         Get
            Return Me.my_number
        End Get
        Set(ByVal value As Integer)
            Me.my_number = value
            form1.Incluida.atributoC21=value
        End Set
    End Property
End Class


Espero haberte aclarado algunas cosas y espero que sea lo que buscas, si tienes dudas no te cortes en preguntar.



novalida

Hola ABDERRAMAH, muchas gracias por tu repuesta :)

No he utilizado propiedades para minimizar el código del ejemplo que he puesto, pero su implementación es una de las que considero buenas prácticas que intento recordar, pero de todas formas mcuhas gracias por tu detallada explicación :)

No entiendo muy bien la asignación que realizas en el último código que has escrito:



Public Class testclass1
    Private my_number As Integer = 0

    Public Property number As Integer
         Get
            Return Me.my_number
        End Get
        Set(ByVal value As Integer)
            Me.my_number = value
            form1.Incluida.atributoC21=value
        End Set
    End Property
End Class



En especial esto:



form1.Incluida.atributoC21=value



Si es de la manera que indicas, ¿entonces mis clases quedarían así?



    Public Class Principal
        Public objeto1 As ClaseIncluida1
        Public objeto2 As ClaseIncluida2
        Public total As Integer
    End Class

    Public Class ClaseIncluida1
        Private _atributoC11 As Integer
        Public _ atributoC12 As Integer
   
        Public Property atributoC11 As Integer
            Get
                Return _atributoC11
            End Get

            Set(ByVal value As Integer)
                _atributoC11 = value
                Principal.objeto2._atributoC21 = value             
            End Set
        End Property
    End Class

    Public Class ClaseIncluida2
        Public _atributoC21 As Integer
        Public _atributoC22 As Integer
    End Class




El error que me indica Visual Studio es La referencia a un miembro no compartido requiere una referencia de objeto.

Creo que es algo similar a lo que me salía intentado hacerlo con eventos  :-(

ABDERRAMAH

El problema es que no accedes desde el principio de la estructura. Fíjate que yo no hago:
CitarIncluida.atributoC21=value

sino que accedo desde form1
CitarForm1.Incluida.atributoC21=value

form1 es mi formulario principal, de esta forma incluso puedes modificar cosas en otros formularios hijos (al fin y al cabo un formulario es un objeto) por ejemplo, desde el formulario 1 creo dos formularios más:
Citar
public x as new form2
public y as new form3

ahora, en el código de form3 puedo hacer:

Citarform1.x.title="funcionó"

y así modifico desde y (form3) un valor de x (form2) pero fijate que tengo que acceder desde form1 puesto que es quien creó todo lo demás.

novalida

Muy buenas de nuevo ABDERRAMAH!!! :)

Creo que más que acceder desde el principio de la estructura es acceder desde una instancia de la clase Principal, que es lo que me indicas tú al realizar ese acceso desde un formulario, dado que la instancia de la clase que llamas Incluida se encuentra en dicho formulario.

Yo quería que la clase Principal hiciera automáticamente esos comportamientos sin tener que realizarlos desde clases externas como formularios en los que se instanciará dicha clase Principal.

Había pensado que mediante delegados y eventos podría hacerlo, pero me encuentro con problemas similares al intentar acceder a una clase desde otra estando las dos contenidas en una.

Esto parece un poco lío, pero creo que con el código de mi primer mensaje está claro... o eso creo :S

Mediante delegados y eventos ¿¿podría realizar lo que quiero??

Insisto en usar delegados y eventos dado que me parece importante aprender su uso.