WPF mit VB.NET / TextBox an Property binden

  • WPF

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von Veronesi.

    WPF mit VB.NET / TextBox an Property binden

    Hallo Zusammen

    Ich weiss, zu dieser Frage gibt es sehr, sehr viele Antworten im Internet.
    Aber trotz intensiver Suche habe ich mein Test nicht zu laufen gebracht.

    Wie kann ich meine TextBox in WPF an eine Property binden?
    (INotifyPropertyChanged ist natürlich implementiert)

    Hier der XAML Code:

    XML-Quellcode

    1. <Window x:Class="MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. Title="MainWindow" Height="87" Width="236">
    5. <Grid>
    6. <TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="TextBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=UpdateProperties.StatusLabel1}"/>
    7. <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="135,10,0,0" Name="Button1" VerticalAlignment="Top" Width="75" />
    8. </Grid>
    9. </Window>


    Und hier der VB.NET Code:

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Class MainWindow
    3. Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
    4. Dim Update As New UpdateProperties
    5. Update.StatusLabel1 = Now.Second.ToString
    6. End Sub
    7. End Class
    8. Public Class UpdateProperties
    9. Implements INotifyPropertyChanged
    10. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    11. Private Sub NotifyPropertyChanged(ByVal info As String)
    12. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    13. End Sub
    14. Private _StatusLabel1 As String
    15. Public Property StatusLabel1 As String
    16. Get
    17. Return _StatusLabel1
    18. End Get
    19. Set(value As String)
    20. If _StatusLabel1 <> value Then
    21. _StatusLabel1 = value
    22. NotifyPropertyChanged("StatusLabel1")
    23. End If
    24. End Set
    25. End Property
    26. End Class


    Alles in .NET 4.0

    Was ist mein Fehler?

    Veronesi
    IM Window-Xaml gibts kein DataContext, und das Binding ist nicht richtig definiert.
    Mach sowas am besten übers PropertyFenster - dazu isses da: Binding-Picking im Xaml-Editor

    edit: na, ich versuchma

    XML-Quellcode

    1. <Window x:Class="MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. xmlns:my="MyRootnamespaceUndRichtigeSyntaxBitte"
    5. Title="MainWindow" Height="87" Width="236">
    6. <Window.DataContext>
    7. <my:UpdateProperties>
    8. </Window.DataContext>
    9. <Grid>
    10. <TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="TextBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=StatusLabel1}"/>
    11. <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="135,10,0,0" Name="Button1" VerticalAlignment="Top" Width="75" />
    12. </Grid>
    13. </Window>
    Es hängt hier am richtigen Setzen des my-xmlns.

    Und UpdateProperties sollte auch in eine Extra-Viewmodel-Datei - nicht einfach ins CodeBehind klatschen.

    edit: nee - so wird das nix. Das mittm ButtonClick sollte über den Command-Pattern laufen - mit einem RelayCommand(DelegateCommand heißt das ab 2012).
    Also gugge obiges Tut, um Binding-Picking in Aktion zu sehen, und gugge 4ViewsWpf, um zu lernen, wie man ein Anwendungsweites MainViewmodel bereitstellt, was dann auch Commands empfängt.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Hallo ErfinderDesRades

    Vielen Dank für Deine Antwort.
    Nun habe ich den XAML Code folgendermassen geändert. (Bin totaler Anfänger)
    Mein Projekt heisst "test", deshalb der clr-namespace:test


    XML-Quellcode

    1. <Window x:Class="MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. Title="MainWindow" Height="87" Width="236"
    5. xmlns:Update="clr-namespace:test">
    6. <Window.DataContext>
    7. <Update:UpdateProperties/>
    8. </Window.DataContext>
    9. <Grid>
    10. <TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="TextBox1" VerticalAlignment="Top" Width="120" Text="{Binding StatusLabel1}"/>
    11. <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="135,10,0,0" Name="Button1" VerticalAlignment="Top" Width="75" />
    12. </Grid>
    13. </Window>


    Leider immer noch ohne Erfolg.
    Auch mit Deinem Video bin ich (bisher) nicht auf die Lösung gekommen.

    Könntest Du mir bitte nochmals helfen?
    sieht doch richtig aus - die Textbox müsste nun doch was anzeigen.

    achso: belege mal UpdateProperties.StatusLabel1 mit einem Defaultwert, dass du siehst, das gebunden ist:

    VB.NET-Quellcode

    1. Private _StatusLabel1 As String="<Default>"
    2. Public Property StatusLabel1 As String
    3. Get
    4. Return _StatusLabel1
    5. End Get
    6. Set(value As String)
    7. If _StatusLabel1 <> value Then
    8. _StatusLabel1 = value
    9. NotifyPropertyChanged("StatusLabel1")
    10. End If
    11. End Set
    12. End Property
    Hallo!

    Ja, nun habe ich gesehen, dass die TextBox den Startwert anzeigt.
    Leider wird er nie updated.

    Ich habe das mit dem Button mal auskommentiert und einen Timer eingefügt, der alle Sekunde die aktuellen Sekunden in die Property schreibt.
    Doch das wird nicht updated.

    Ich verstehe leider noch viel zu wenig von der Materie.
    Kannst Du mir bitte hier noch helfen?

    Vielen Dank schon mal!

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Class MainWindow
    3. Public ClockTimer As New System.Timers.Timer()
    4. Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
    5. AddHandler ClockTimer.Elapsed, AddressOf ClockTimer_Tick
    6. ClockTimer.Interval = 1000
    7. ClockTimer.Enabled = True
    8. End Sub
    9. Private Sub ClockTimer_Tick(sender As Object, e As EventArgs)
    10. Dim Update As New UpdateProperties
    11. Update.StatusLabel1 = Now.Second.ToString
    12. Debug.WriteLine(Update.StatusLabel1)
    13. End Sub
    14. 'Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs)
    15. ' Dim Update As New UpdateProperties
    16. ' Update.StatusLabel1 = Now.Second.ToString
    17. 'End Sub
    18. End Class
    19. Public Class UpdateProperties
    20. Implements INotifyPropertyChanged
    21. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    22. Private Sub NotifyPropertyChanged(ByVal info As String)
    23. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    24. End Sub
    25. Private _StatusLabel1 As String = "Startwert"
    26. Public Property StatusLabel1 As String
    27. Get
    28. Return _StatusLabel1
    29. End Get
    30. Set(value As String)
    31. If _StatusLabel1 <> value Then
    32. _StatusLabel1 = value
    33. NotifyPropertyChanged("StatusLabel1")
    34. End If
    35. End Set
    36. End Property
    37. End Class
    OK, mir fehlen massiv Grundlagen, das stimmt.
    Ich versuche mir diese einfach in verschiedenen Übungen anzueignen.
    Und bei diesen Übungen kommen immer wieder Gedanken wie: Es wäre doch nett, in der Statusleiste die aktuelle Zeit anzuzeigen - bloss als Übung.

    Und dann bin ich beim Binding gelandet......

    Also mit dem Schlüsselwort New wird jedesmal die Klasse neu instanziert. Ist wohl Blödsinn!

    Aber auch wenn ich diese Update Variable am Anfang nur einmal deklariere, funktioniert es (noch) nicht.
    Ich denke mir das so:
    Wenn ich jedes Mal die Klasse neu instanziere, werden auch jedes Mal alle darin enthaltenen Variablen / Properties / Events neu "deklariert".
    Und wenn z.B. die Variablen neu erstellt werden, haben sie den jeweiligen Default Wert.

    Also - so meine sehr begrenzte Sicht der Dinge - darf ich die Klasse nur einmal (am Anfang) deklarieren (Instanzieren) und danach immer wieder diesen Objektverweis für den Zugriff auf die Properties darin verwenden.

    In meinem Fall wäre der Objektverweis also Update.

    Stimmt das soweit (Laienhaft ausgedrückt)?
    Vielen Dank für Deine Geduld bisher.

    Nachfolgend mein aktueller Code.
    Deklariert wird sie doch ganz am Anfang, oder sehe ich das falsch?

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Class MainWindow
    3. Public ClockTimer As New System.Timers.Timer()
    4. Public Update As New UpdateProperties
    5. Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
    6. InitializeComponent()
    7. AddHandler ClockTimer.Elapsed, AddressOf ClockTimer_Tick
    8. ClockTimer.Interval = 1000
    9. ClockTimer.Enabled = True
    10. End Sub
    11. Private Sub ClockTimer_Tick(sender As Object, e As EventArgs)
    12. Update.StatusLabel1 = Now.Second.ToString
    13. End Sub
    14. End Class
    15. Public Class UpdateProperties
    16. Implements INotifyPropertyChanged
    17. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    18. Private Sub NotifyPropertyChanged(ByVal info As String)
    19. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    20. End Sub
    21. Private _StatusLabel1 As String = "Startwert"
    22. Public Property StatusLabel1 As String
    23. Get
    24. Return _StatusLabel1
    25. End Get
    26. Set(value As String)
    27. If _StatusLabel1 <> value Then
    28. _StatusLabel1 = value
    29. NotifyPropertyChanged("StatusLabel1")
    30. End If
    31. End Set
    32. End Property
    33. End Class
    du meinst in zeile#5?

    Nein.
    Da wird zwar auch eine UpdateProperties-Instanz deklariert, und im Folgenden wird auch damit gearbeitet, aber das ist leider nicht die UpdateProperties-Instanz, an die deine Textbox gebunden ist.

    Aber wieso hast du den Timer eigentlich in der Window-Classe instanziert?

    kann der nicht in die UpdateProperties-Klasse?

    Also in der Window-Klasse kannste alles weglöschen.
    Ja, ich meine Zeile #5.

    Siehst Du, und genau das ist mein Problem.
    Du schreibst, das sei nicht die UpdateProperties Instanz, an welche meine TextBox gebunden ist.

    Das verstehe ich eben nicht. Wie und wo muss ich das denn machen?
    Und wo würdest Du bzw. wo sollte man korrekterweise den Timer denn instanzieren?

    Edit:

    Ach so!!!
    Jetzt hab ich das halbwegs kapiert:

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Class MainWindow
    3. End Class
    4. Public Class UpdateProperties
    5. Implements INotifyPropertyChanged
    6. Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    7. Public ClockTimer As New System.Timers.Timer()
    8. Public Sub New()
    9. AddHandler ClockTimer.Elapsed, AddressOf ClockTimer_Tick
    10. ClockTimer.Interval = 1000
    11. ClockTimer.Enabled = True
    12. End Sub
    13. Private Sub ClockTimer_Tick(sender As Object, e As EventArgs)
    14. StatusLabel1 = Now.Second.ToString
    15. End Sub
    16. Private Sub NotifyPropertyChanged(ByVal info As String)
    17. RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    18. End Sub
    19. Private _StatusLabel1 As String = "Startwert"
    20. Public Property StatusLabel1 As String
    21. Get
    22. Return _StatusLabel1
    23. End Get
    24. Set(value As String)
    25. If _StatusLabel1 <> value Then
    26. _StatusLabel1 = value
    27. NotifyPropertyChanged("StatusLabel1")
    28. End If
    29. End Set
    30. End Property
    31. End Class


    XML-Quellcode

    1. <Window x:Class="MainWindow"
    2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    4. Title="MainWindow" Height="87" Width="236"
    5. xmlns:Update="clr-namespace:test">
    6. <Window.DataContext>
    7. <Update:UpdateProperties/>
    8. </Window.DataContext>
    9. <Grid>
    10. <TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="TextBox1" VerticalAlignment="Top" Width="120" Text="{Binding StatusLabel1}"/>
    11. </Grid>
    12. </Window>


    Und dann funktioniert es!

    Vielen herzlichen Dank!
    Ich werde nun versuchen, das ganze zu verstehen!

    Nochmals herzlichen Dank!
    Veronesi

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Veronesi“ ()

    Super. Vielen Dank!
    Noch eine letzte Frage:
    In XAML wurde ja der DataContext angegeben:

    <Window.DataContext>
    <Update:UpdateProperties/>
    </Window.DataContext>

    Kann man das auch nur auf das Grid anwenden, in welchem die TextBox liegt?
    Ich könnte mir vorstellen, dass ich evtl. (irgendwann mal) zwei unterschiedliche DataContext haben müsste. (Wegen der Übersichtlichkeit)

    Edit: So geht's schon mal nicht:

    XML-Quellcode

    1. <Grid DataContext="Update:UpdateProperties}">
    2. <TextBox Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="TextBox1" VerticalAlignment="Top" Width="120" Text="{Binding StatusLabel1}"/>
    3. </Grid>
    Ja - das ist das Konzept von DataContext in Wpf - prinzipiell ist das vorgesehen - nur mit der richtigen Syntax halt.

    Aber ich mag dir jetzt nicht jedes einzelne Konzept individuell erläutern. Lies ein gutes Buch, lies MVVM–Pattern (Josh Smiths Artikel)
    geh nach Wpf lernen vor, (probier meine Tuts durch ;))