none
Klasse und Event/handle RRS feed

  • Frage

  • Hallo Experten,

    die Klassen und Ihre Möglichkeiten ist ein weites Feld um es mit den Worten von G.Grass zusagen. Ich habe mal folgende mini-Klasse definiert.

    Public Class Projekt
        Dim temp As String
        Public Sub New()
            temp = InputBox("Neuer Projektname festlegen", "Neues Projekt", "")
            If temp = "" Then Exit Sub
            Me.Name = temp
        End Sub
        Private _Name As String
        Public Property Name() As String
            Get
                Return _Name
            End Get
            Set(ByVal value As String)
                _Name = value
            End Set
        End Property
    End Class

    ich würde nun gerne ein Ereignis definieren nach dem Muster von einer Textbox_TextChanged(...) in Bezug auf das Property Name(). Geht das und wenn ja wo und wie ....

    mfg eem monarch

    Samstag, 18. Februar 2012 14:04

Antworten

  • Hallo,

    am einfachsten ist es i. a. die INotifyPropertyChanged Schnittstelle zu verwenden,
    siehe Gewusst wie: Implementieren der INotifyPropertyChanged-Schnittstelle
    was die Zahl der Ereignisse im Rahmen hält, wenn die Klasse mal nicht mehr so "Mini" ist.

    Vorteil ist dabei, dass auch die Windows Forms (und WPF) Datenbindung damit umgehen kann,
    wie schon mal angedeutet in Array in Strukturvariable

    Verwendet man explizite Ereignisse, so müssen sie dazu nach dem Muster <Eigenschaftsname>Changed gebildet werden:
    Gewusst wie: Anwenden des PropertyNameChanged-Musters

    @Markus: Der "_" wäre dabei ein Unterstrich zuviel.

    Gruß Elmar

    • Als Antwort markiert Monarch-Falter Mittwoch, 22. Februar 2012 14:17
    Samstag, 18. Februar 2012 16:59
    Beantworter
  • Hi Monarch,

    hier mal Beispiel für die Implementierung von Implements INotifyPropertyChanged.

    Imports System.ComponentModel
    Public Class Person
        Implements INotifyPropertyChanged
    
        Protected Sub OnPropertyChanged(ByVal name As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
        End Sub
    
        Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    
        Private mName As String = String.Empty
        Public Property Name As String
            Set(ByVal value As String)
                mName = value
                OnPropertyChanged("Name")
            End Set
            Get
                Return mName
            End Get
        End Property
    
    End Class

    MFG

    Björn

    • Als Antwort markiert Monarch-Falter Mittwoch, 22. Februar 2012 14:16
    Montag, 20. Februar 2012 18:52
  • Hallo Monarch, du musst Bücher lesen um etwas mit VB.Net zu machen was einfach nur einen Nutzen bringt. Ich war durch diese Zeitung so beunruhigt. Doch ich denke das dieser Hype sehr gelassen gesehen werden kann.

    Option Strict On
    Imports System
    Imports System.IO

    Public Class xSituationen
      Public Property index As Integer    'Index für Ursprüngliche Reihenfolge
      Public Property Situation As String
      Public Property Antw As New List(Of String)
      Public Property Stil As New List(Of Integer)
      Public Property Wert As New List(Of Integer)
      Public Property Reife As Integer
    End Class

    Public Class Projekt
      Private mstrName As String = "Property welches gesetzt sein muss."
      Private Situation As List(Of xSituationen)

      Public ReadOnly Property Name As String
        Get
          Return mstrName
        End Get
      End Property

      Public Sub New(ByVal pstrName As String)
        mstrName = pstrName
        Situation = New List(Of xSituationen)
      End Sub

      Public Sub Read()
        Dim i As Integer = 0
        Dim objxSituationen As xSituationen

        ' Variable die den Text aufnimmt
        Dim textline As String

        ' Nun über StreamReader einlesen (ich verwende Using, das räumt sich selbst auf)
        Using lese As New System.IO.StreamReader(System.AppDomain.CurrentDomain.BaseDirectory & "\Projekte\" & Me.Name & "\Data\situationen.dat", System.Text.Encoding.Default)
          Do While Not lese.EndOfStream
            objxSituationen = New xSituationen
            i += 1
            textline = lese.ReadLine
            Debug.Print(textline)
            Dim sArray() As String
            sArray = Split(textline, "|")

            objxSituationen.index = i
            objxSituationen.Situation = sArray(0)
            objxSituationen.Antw = New List(Of String) From {sArray(1), sArray(2), sArray(3), sArray(4)}
            objxSituationen.Stil = New List(Of Integer) From {CInt(sArray(5)), CInt(sArray(6)), CInt(sArray(7)), CInt(sArray(8))}
            objxSituationen.Wert = New List(Of Integer) From {CInt(sArray(9)), CInt(sArray(10)), CInt(sArray(11)), CInt(sArray(12))}

            Situation.Add(objxSituationen)
          Loop
        End Using
      End Sub

    End Class


    • Bearbeitet Markus222 Montag, 20. Februar 2012 19:30
    • Als Antwort markiert Monarch-Falter Mittwoch, 22. Februar 2012 14:16
    Montag, 20. Februar 2012 19:15

Alle Antworten

  • Hallo Monarch,

    vielleicht so:

    Public Class Projekt
      Event Name_Changed()

      Dim temp As String = ""
      Public Sub New()
        temp = InputBox("Neuer Projektname festlegen", "Neues Projekt", "")
        If temp = "" Then Exit Sub
        Me.Name = temp
      End Sub

      Private _Name As String = ""
      Public Property Name() As String
        Get
          Return _Name
        End Get

        Set(ByVal value As String)
          Dim blnChanged As Boolean = False

          If _Name <> Trim(value) Then
            blnChanged = True
          End If
          _Name = Trim(value)
          If blnChanged Then
            RaiseEvent Name_Changed()
          End If
        End Set
      End Property
    End Class


    Public Class Form1
      WithEvents Projekt As New Projekt

      Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Projekt.Name = "Projekt1"
        Projekt.Name = "Projekt2"
      End Sub

      Private Sub Projekt_Name_Changes() Handles Projekt.Name_Changed
        MsgBox(Projekt.Name)
      End Sub

    End Class

    Samstag, 18. Februar 2012 15:05
  • Hallo,

    am einfachsten ist es i. a. die INotifyPropertyChanged Schnittstelle zu verwenden,
    siehe Gewusst wie: Implementieren der INotifyPropertyChanged-Schnittstelle
    was die Zahl der Ereignisse im Rahmen hält, wenn die Klasse mal nicht mehr so "Mini" ist.

    Vorteil ist dabei, dass auch die Windows Forms (und WPF) Datenbindung damit umgehen kann,
    wie schon mal angedeutet in Array in Strukturvariable

    Verwendet man explizite Ereignisse, so müssen sie dazu nach dem Muster <Eigenschaftsname>Changed gebildet werden:
    Gewusst wie: Anwenden des PropertyNameChanged-Musters

    @Markus: Der "_" wäre dabei ein Unterstrich zuviel.

    Gruß Elmar

    • Als Antwort markiert Monarch-Falter Mittwoch, 22. Februar 2012 14:17
    Samstag, 18. Februar 2012 16:59
    Beantworter
  • Servus Markus,

    funzen tut das, ist aber irgendwie doppelt gemoppelt. Innerhalb des Set's wird die Änderung ermittelt und der RaiseEvent ausgelöst. Es würde aber auch nix ändern wenn ich den Event innerhalb des Set's lasse, oder ?

    mfg eem monarch

    Sonntag, 19. Februar 2012 12:02
  • Hallo Manarch,

    Elmas Lösung ist auf jeden fall die Richtige und du solltest sie verwenden. 

    Was deine Frage angeht, die Deklaration des Events mus auserrhalb des Set´s geschehen, damit eine andere Klasse, ein Handel auf das Event setzen kann.

    Das RaiseEvent kann dann im Set gesehen.

    Noch eine kleine Anmerkung zum Set vom Markus:

      Set(ByVal value As String)
          Dim blnChanged As Boolean = False
    
          If _Name <> Trim(value) Then
            blnChanged = True
          End If
          _Name = Trim(value)
          If blnChanged Then
            RaiseEvent Name_Changed()
          End If
        End Set
      End Property
    End Class

    Kann man auch so schreiben:

     Set(ByVal value As String)
          
          If _Name <> value Then
             _Name = value
             RaiseEvent Name_Changed()
          End If
       
    End Set
     

    Erstmal ist es kürzer und einfacher zu lesen.

    Zweitens habe ich, das Trim entfernt. Man kann es natürlich machen, aber für mich ändert das Trim, dass Verhalten des Setters ohne dass es für einen anderen Programierer ersichtlich ist. Wenn z.B. der Name bei einen Passwort genutzt wir, kann es durchaus sein das jemand am Anfang ein Leerzeichen benutzt. Hier dann herauszu finden, das dein Setter das Leerzeichen entfernt ist dann nicht ganz Trivial.

    Es bietet sich hier der DataErrorProvider (bwz das Interface) an, man könnte auch eine Exeption schmeißen, was ich aber nicht so schön finde.

    MFG

    Björn 

    Sonntag, 19. Februar 2012 13:28
  • Servus Markus,

    funzen tut das, ist aber irgendwie doppelt gemoppelt. Innerhalb des Set's wird die Änderung ermittelt und der RaiseEvent ausgelöst. Es würde aber auch nix ändern wenn ich den Event innerhalb des Set's lasse, oder ?

    mfg eem monarch

    Hallo Monarch,

    das verstehe ich nicht. Würde nicht sagen dass es doppelt gemoppelt ist. Du kannst ja einfach probieren und schauen.

    Sonntag, 19. Februar 2012 15:30
  • Ok,

    die Antwort von Palin erklärt es. Wenn ich den Event in verschiedenen Klassen benutzen will, muss ich das RaiseEvent verwenden. Ansonsten könnte ich ja folgendes machen (nur als Beispiel)

     Set(ByVal value As String)
         
         
    If _Name <> value Then

             if value="x" then _Name="Fehler" else   _Name = value
             '
    RaiseEvent Name_Changed()
         
    End If
      
    End Set
     

    Montag, 20. Februar 2012 10:40
  • Hallo Björn,

    danke, verstanden. Was Elmar angeht, so sind seine Antworten immer richtig, nur das Verstehen von meiner Seite ist es nicht weit her. Habe die Links gelesen, steige aber noch nicht durch.

    danke mfg eem monarch

    Montag, 20. Februar 2012 10:43
  • Servus Elmar,

    bin am lesen steige aber noch nicht durch.

    melde mich wieder .... danke mfg eem monarch

    Montag, 20. Februar 2012 10:43
  • Hallo Monarch,

    es kommt darauf an was du machen willst. Die einfachste und am einfachsten zu lesenste Lösung ist im Zweifelsfalle meiner Meinung nach die Beste. Das "State of the Art" oder wie man es nennen mag zieht im Quellcode immer ein Nichtverstehen nach sich. Man muss lange suchen. Der Quellcode erklärt sich nicht mehr selbst. Je mehr davon du nimmst desto mehr must du suchen nach einigen Monaten und Jahren um es wieder zu kapieren. Je einfacher und nativer VB du nimmst und dabei so kurz wie möglich desto einfacher ist dein Programm zu verstehen.

    Montag, 20. Februar 2012 16:32
  • Na prima,

    bin nur am kämpfen, folgender Code führt zu Fehlermeldungen, wenn ich z.B xSituationen.index einen Wert zuweise. Ich lese nun seit stunden auch das von Elmar aber komme nicht dahinter. Wenn ich das ganze ohne Klassen und List - Objekten schreibe, geht das fix und funzt ... macht man aber nicht mehr, hab ich mir sagen lassen.

    Also, wo liegt der Fehler .....

    Imports System
    Imports System.IO
    Public Class xSituationen
        Public Property index As Integer    'Index für Ursprüngliche Reihenfolge
        Public Property Situation As String
        Public Property Antw As New List(Of String)
        Public Property Stil As New List(Of Integer)
        Public Property Wert As New List(Of Integer)
        Public Property Reife As Integer
    End Class
    Public Class Projekt
        Inherits List(Of xSituationen)
    
        Public Sub Read()
            Dim i As Integer = 0
            Dim Situation As New List(Of xSituationen)
    
    
            ' Variable die den Text aufnimmt
            Dim textline As String
    
            ' Nun über StreamReader einlesen (ich verwende Using, das räumt sich selbst auf)
            Using lese As New System.IO.StreamReader(System.AppDomain.CurrentDomain.BaseDirectory & "\Projekte\" & Me.Name & "\Data\situationen.dat", System.Text.Encoding.Default)
                Do While Not lese.EndOfStream
                    i += 1
                    textline = lese.ReadLine
                    Debug.Print(textline)
                    Dim sArray() As String
                    sArray = Split(textline, "|")
    
                    xSituationen.index = i
                    xSituationen.Situation = sArray(0)
                    xSituationen.Antw = New List(Of String) From {sArray(1), sArray(2), sArray(3), sArray(4)}
                    xSituationen.Stil = New List(Of Integer) From {CInt(sArray(5)), CInt(sArray(6)), CInt(sArray(7)), CInt(sArray(8))}
                    xSituationen.Wert = New List(Of Integer) From {CInt(sArray(9)), CInt(sArray(10)), CInt(sArray(11)), CInt(sArray(12))}
    
                    Situation.Add(xSituationen)
                Loop
            End Using
        End Sub
        'Public Sub 

    Montag, 20. Februar 2012 18:26
  • Hi Monarch,

    wenn ich das gerade richtig sehe hast du keine Instanz (und VAriabel)  von xSituation und kannst dem ensptächend darauf zugreifen.

    Die Fehlermeldung wäre natürlich auch interessant.

    MFG

    Björn

    Montag, 20. Februar 2012 18:44
  • Fehlermeldung

    Der Verweis auf einen nicht freigegeben Member erfordert einen Objektverweis....

    Bringt mich nicht weiter .... dich vielleicht

    Montag, 20. Februar 2012 18:52
  • Hi Monarch,

    hier mal Beispiel für die Implementierung von Implements INotifyPropertyChanged.

    Imports System.ComponentModel
    Public Class Person
        Implements INotifyPropertyChanged
    
        Protected Sub OnPropertyChanged(ByVal name As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
        End Sub
    
        Public Event PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    
        Private mName As String = String.Empty
        Public Property Name As String
            Set(ByVal value As String)
                mName = value
                OnPropertyChanged("Name")
            End Set
            Get
                Return mName
            End Get
        End Property
    
    End Class

    MFG

    Björn

    • Als Antwort markiert Monarch-Falter Mittwoch, 22. Februar 2012 14:16
    Montag, 20. Februar 2012 18:52
  • Hallo Monarch, du musst Bücher lesen um etwas mit VB.Net zu machen was einfach nur einen Nutzen bringt. Ich war durch diese Zeitung so beunruhigt. Doch ich denke das dieser Hype sehr gelassen gesehen werden kann.

    Option Strict On
    Imports System
    Imports System.IO

    Public Class xSituationen
      Public Property index As Integer    'Index für Ursprüngliche Reihenfolge
      Public Property Situation As String
      Public Property Antw As New List(Of String)
      Public Property Stil As New List(Of Integer)
      Public Property Wert As New List(Of Integer)
      Public Property Reife As Integer
    End Class

    Public Class Projekt
      Private mstrName As String = "Property welches gesetzt sein muss."
      Private Situation As List(Of xSituationen)

      Public ReadOnly Property Name As String
        Get
          Return mstrName
        End Get
      End Property

      Public Sub New(ByVal pstrName As String)
        mstrName = pstrName
        Situation = New List(Of xSituationen)
      End Sub

      Public Sub Read()
        Dim i As Integer = 0
        Dim objxSituationen As xSituationen

        ' Variable die den Text aufnimmt
        Dim textline As String

        ' Nun über StreamReader einlesen (ich verwende Using, das räumt sich selbst auf)
        Using lese As New System.IO.StreamReader(System.AppDomain.CurrentDomain.BaseDirectory & "\Projekte\" & Me.Name & "\Data\situationen.dat", System.Text.Encoding.Default)
          Do While Not lese.EndOfStream
            objxSituationen = New xSituationen
            i += 1
            textline = lese.ReadLine
            Debug.Print(textline)
            Dim sArray() As String
            sArray = Split(textline, "|")

            objxSituationen.index = i
            objxSituationen.Situation = sArray(0)
            objxSituationen.Antw = New List(Of String) From {sArray(1), sArray(2), sArray(3), sArray(4)}
            objxSituationen.Stil = New List(Of Integer) From {CInt(sArray(5)), CInt(sArray(6)), CInt(sArray(7)), CInt(sArray(8))}
            objxSituationen.Wert = New List(Of Integer) From {CInt(sArray(9)), CInt(sArray(10)), CInt(sArray(11)), CInt(sArray(12))}

            Situation.Add(objxSituationen)
          Loop
        End Using
      End Sub

    End Class


    • Bearbeitet Markus222 Montag, 20. Februar 2012 19:30
    • Als Antwort markiert Monarch-Falter Mittwoch, 22. Februar 2012 14:16
    Montag, 20. Februar 2012 19:15
  • z.B.

    http://www.amazon.de/gp/offer-listing/382732646X/ref=sr_1_3_olp?ie=UTF8&qid=1329770603&sr=8-3&condition=new

    Ich glaube je umfangreicher die Sprache wird desto mehr stürzen sich die (oft altgedienten) Autoren auf die neuen Features und wälzen diese über Gebühr breit. Mehr Seiten als wirklichen Nutzen. Das worüber früher Bücher geschrieben wurden (wie z.B. Vererbung und andere objektorientierte Konzepte) wird auf ein paar Seiten abgehandelt und kann in seiner revolutionären Bedeutung von Neulingen gar nicht durch das Buch erfasst werden. Evtl. wäre es daher für einen echten Einsteiger in VB.Net wirklich gut mit einem Buch von VB.Net 2005 zu beginnen. Und dann eben ein Buch zu 2008 und danach eins zu 2010.

    Montag, 20. Februar 2012 20:54
  • Fehlermeldung

    Der Verweis auf einen nicht freigegeben Member erfordert einen Objektverweis....

    Bringt mich nicht weiter .... dich vielleicht

    Hätte ich beine Übersehen. ;)

    Ich denke, dass ist der Punkt den ich oben schon angesprochen haben.

    Du must dier eine Instanz des Objektes erzeugen.

    Füge mal an anfang der Sclheife das ein:

     private tempxSituationen as xSituation = new Situation()

    und ersetze in der Schleife xSituation durcfh tempxSituation.

    Damit erzeugst du bei jedem Schleifen durchlauf ein neues Objekt von xSituation (Ich denk mal das möchtest du hier machen).

    Wenn du es vor der Schleife machst fügst du der Liste immer das gleiche Objekt hinzu.

    Dann hast du zwar x Verweise in der Liste aber immer auf der gleiche Objekt, welches die gleichen Werte hat.

    MFG

    Björn

    Montag, 20. Februar 2012 21:36
  • Also erstmal danke allen,

    funzt jetzt ... Da ich mich zwanghaft mit dem VB beschäftigen muss, habe ich halt die Probleme. Ich komme aus der DB-Ecke. Anyway, habe mich mit einen Pratiker unterhalten, der mir folgendes gesagt hat zum Thema Klassen und Neuerungen in VB. Man sollte nicht alles zur Religion erheben bzw. man sollte nicht mit einem 40 to ein Kasten Bier abholen. Klassen haben ihre Vorteile, welche aber in Single-, Klein etc. Programme oft mit zuviel Aufwand verbunden sind. Außerdem muss man nicht alles und jedes als Objekt behandeln bzw. definieren.

    trotzdem, werde ich mich weiter bemühen ... danke mfg eem  Monarch.

    PS: Das nächste Problem kommt bestimmt, werde jetzt erstmal versuchen, die Klasse voll funiktionsfähig zu machen. :-)

    Dienstag, 21. Februar 2012 18:00