none
Button isEnabled Eigenschaft an Klasseneigenschaft binden RRS feed

  • Frage

  • hallo alle zusammen - leider funktioniert ein Databinding aus einer Klasse an einen Button nicht

    In meiner Klasse wird die boolsche Eigenschaft "bSave_enabled" abhängig vom Validierungsstatus einiger anderer Eigenschaften gesetzt. In meinem Formular soll nun ein Button zum Speichern der eventuellen Änderungen über Databinding den Zustand der Eigenschaft "bSave_enabled" (true oder false) reflektieren. Dazu wurde im XAML-Code die Butteneigenschaft "isEnabled" über Databinding mit der Klassenvariable verbunden. Nachstehend der XAML-Code.

    <Button Name="btn_Speichern" DataContext="cTPT" IsEnabled="{Binding Path=bSave_enabled}" Content="Speichern" Grid.Column="5" Grid.Row="1" Height="auto" HorizontalAlignment="Stretch" Margin="0" VerticalAlignment="Stretch" Width="auto" />
    
    
    
    

    Nachstehend der VB.NET Code:

    Implements INotifyPropertyChanged
    
    
    
     Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
    
    
    
     Private Sub NotifyPropertyChanged(ByVal info As String)
    
    
    
     RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info)) 
    
    
    
     End Sub
    
    
    
    
    
    
    
     Public Property bSave_enabled As Boolean
    
    
    
     Get
    
    
    
      bSave_enabled = mvarbSave_enabled
    
    
    
     End Get
    
    
    
     Set(ByVal value As Boolean)
    
    
    
      mvarbSave_enabled = value
    
    
    
      NotifyPropertyChanged("bSave_enabled")
    
    
    
     End Set
    
    
    
     End Property
    
    
    
    

    Selbst wenn ich von aussen die Klasseneigenschaft bSave_enabled = false setze, bleibt der Button aktiviert (isEnabled = true).

    Wer hat einen Tipp für mich? Danke im Voraus

     


    Michael Lutz, BITsoft
    Donnerstag, 20. Januar 2011 17:44

Antworten

  • MVVM ist eine sehr einfache Möglichkeit, Oberfläche und Programmlogik
    vollständig zu trennen. Damit ist es möglich, die Programmlogik ohne
    Bedieneraufwand zu testen, z.B. mit Unittests. Bei in der Oberfläche
    integrierter Programmlogik (Codebehind) ist so etwas nicht oder nur
    teilweise möglich.
     
    --
    Viele Grüße
    Peter
     
     
    • Als Antwort markiert BITsoft_mlutz Freitag, 21. Januar 2011 21:24
    Freitag, 21. Januar 2011 15:53

Alle Antworten

  • Das sieht soweit ganz gut aus. Wie hast du denn den DataContext gesetzt?

     

    Freitag, 21. Januar 2011 07:35
    Beantworter
  • Hallo

    DataContext ist einmal in dem Grid gesetzt (XAML), in dem sich der Button befindet und zur Sicherheit sogar noch mal im XAML-Code für den Button selbst (siehe XAML-Code in meiner Anfrage). Definitiv wird nirgends im gesamten Code die Eigenschaft isEnabled des Buttons gesetzt ausser in dem angebundenen Property meiner Klasse (cTPT). Diese Klasse wird im Übrigen Public für die gesamte Anwendung deklariert. Alle anderen DataBindings funktionieren einwandfrei.

    Noch eine Idee?

     


    Michael Lutz, BITsoft
    Freitag, 21. Januar 2011 07:44
  • Sag mal dein Getter des Properties gibt kein Wert zurück. Ist das ein Tipfehler?

     

    Freitag, 21. Januar 2011 07:50
    Beantworter
  • Hallo und danke für die schnelle Kommunikation

    Ich stehe ein bisschen auf dem Schlauch. Der Getter liest den Wert der Variable mvarbSave_enabled. Dieser wird im Setter bestimmt. Oder habe ich deine Frage falsch verstanden?

     


    Michael Lutz, BITsoft
    Freitag, 21. Januar 2011 08:01
  •  Public Property bSave_enabled As Boolean
     Get
     //bSave_enabled = mvarbSave_enabled
     return mvarbSave_enabled; => dies wäre ein korrekter Getter
     End Get
     Set(ByVal value As Boolean)
     mvarbSave_enabled = value
     NotifyPropertyChanged("bSave_enabled")
     End Set
    
     End Property
    
    
    Der Getter muss doch einen return zurückgeben!?
    Freitag, 21. Januar 2011 08:08
    Beantworter
  • Ich mache so etwas über die CanExecute-Möglichkeiten des ICommand-Interfaces. Am einfachsten geht das mit MVVM. Dazu nachfolgend eine Demo zur Anregung. Mit der Eingabe von “xxx” in der TextBox wird der Button anklickbar.
     
    Der XAML-Code:
     
    <Window x:Class="MainWindow"
        Title="MainWindow" Height="300" Width="300"
            xmlns:local="clr-namespace:WpfApplication1">
      <Window.Resources>
        <local:ViewModel x:Key="vm"/>
      </Window.Resources>
      <StackPanel DataContext="{Binding Source={StaticResource vm}}" >
        <TextBox Text="{Binding Txt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        <Button Content="Speichern" Command="{Binding Cmd}"  />
      </StackPanel>
    </Window>
     
    Der ViewModel dazu:
     
    Public Class ViewModel
      Implements INotifyPropertyChanged
     
      Private _txt As String
      Public Property Txt() As String
        Get
          Return _txt
        End Get
        Set(ByVal value As String)
          _txt = value
          OnPropertyChanged("Txt")
        End Set
      End Property
     
      Public ReadOnly Property Cmd As ICommand
        Get
          Return New RelayCommand(New Action(Of Object)(AddressOf cmdExec), AddressOf cmdCanExec)
        End Get
      End Property
     
      Private Sub cmdExec()
        MsgBox("geklickt")
      End Sub
     
      Private Function cmdCanExec() As Boolean
        Return Txt = "xxx"
      End Function
     
      Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
      Private Sub OnPropertyChanged(ByVal prop As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(prop))
      End Sub
     
    End Class
     
    Und der Vollständigkeit halber noch die genutzte RelayCommand-Klasse:
     
    Public Class RelayCommand
      Implements ICommand
      Private ReadOnly _execute As Action(Of Object)
      Private ReadOnly _canExecute As Predicate(Of Object)
      Public Sub New(ByVal execute As Action(Of Object))
        Me.New(execute, Nothing)
      End Sub
      Public Sub New(ByVal execute As Action(Of Object), ByVal canExecute As Predicate(Of Object))
        ' это проверка русского текста
        If execute Is Nothing Then
          Throw New ArgumentNullException("execute")
        End If
        Me._execute = execute
        Me._canExecute = canExecute
      End Sub
      Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute
        Return If(Me._canExecute Is Nothing, True, Me._canExecute(parameter))
      End Function
      Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged
        AddHandler(ByVal value As EventHandler)
          AddHandler CommandManager.RequerySuggested, value
        End AddHandler
        RemoveHandler(ByVal value As EventHandler)
          RemoveHandler CommandManager.RequerySuggested, value
        End RemoveHandler
        RaiseEvent(ByVal sender As System.Object, ByVal e As System.EventArgs)
        End RaiseEvent
      End Event
      Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute
        Me._execute(parameter)
      End Sub
    End Class
     
    --
    Viele Grüße
    Peter
    Freitag, 21. Januar 2011 08:32
  • hallo

    Beide Schreibweisen bringen das gleiche Ergebnis. bSave_enabled = mvarbSave_enabled ist eine Angewohnheit aus VB6-Zeiten. Der Versuch mit Return mvarbSave_enabled bringt keine Veränderung im Verhalten des Buttons. Der Debugger zeigt an, dass der boolsche Wert ständig = false ist. Daher müsste der Button dies über Databinding auch reflektieren. Also gehe ich davon aus, dass aus irgendeinem Umstand zwar der richtige Eigenschaftswert zur Verfügung steht, aber das Databinding nicht angestossen wird bzw. der gebunde Wert der Datensource nicht interpretiert werden kann.


    Michael Lutz, BITsoft
    Freitag, 21. Januar 2011 10:35
  • Danke Peter,

    leider funktioniert das auch in deinem Beispiel (zumindest bei mir) nicht. Unabhängig von der Vorgehensweise MVVM sollte doch mein angedachter Weg funktionieren, oder? Habe ich da einen Denkfehler. Mein Problem ist der Zeitdruck so dass ich nicht komplett neu beginnen und stringend MVVM umsetzen kann.


    Michael Lutz, BITsoft
    Freitag, 21. Januar 2011 11:17
  • Warum mein Beispiel bei Dir nicht funktioniert, kann ich nicht sagen. Wenn
    Du es 1:1 kopiert hast, kann eigentlich nur Deine Framework 4.0-Installation
    fehlerhaft sein. Gerade bei Zeitdruck bietet die Nutzung von MVVM riesige
    Zeitvorteile, da recht einfach die dll's getestet werden können. Ohne MVVM
    ist nicht so einfach möglich und erfordert einen viel größeren Zeit- und
    Arbeitsaufwand, um Probleme zu finden und zu beseitigen.
     
    --
    Viele Grüße
    Peter
     
     
    Freitag, 21. Januar 2011 13:14
  • Danke Peter

    Tatsächlich habe ich dein Beispiel 1:1 ausprobiert. Bzgl. deines Hinweises wegen MVVM muss ich selbstkritisch anmerken, dass ich bestefalls Halbwissen dazu habe. Am Montagmorgen wird einer meiner Mitarbeiter sich nochmals des Problems annehmen und versuchen, dein Beispiel ans Laufen zu bekommen.

    viele Grüße


    Michael Lutz, BITsoft
    Freitag, 21. Januar 2011 14:38
  • MVVM ist eine sehr einfache Möglichkeit, Oberfläche und Programmlogik
    vollständig zu trennen. Damit ist es möglich, die Programmlogik ohne
    Bedieneraufwand zu testen, z.B. mit Unittests. Bei in der Oberfläche
    integrierter Programmlogik (Codebehind) ist so etwas nicht oder nur
    teilweise möglich.
     
    --
    Viele Grüße
    Peter
     
     
    • Als Antwort markiert BITsoft_mlutz Freitag, 21. Januar 2011 21:24
    Freitag, 21. Januar 2011 15:53