none
User Control mit Datenbindung an ein enum funktioniert nicht RRS feed

  • Frage

  • Hallo zusammen,

    in einer Anwendung habe wir auf einer Oberfläche eine Menge von Ventilen und  deren Zustand anzuzeigen.  Für die Darstellung der Ventile haben wir ein eigenes UserControl mit entsprechenden Abhängigkeitseigenschaften definiert, zB eine Eigenschaft IsOpen mit der wir abhängig von einem boolschen Wert das Bild des Ventils ändern.

      //===============================================================================================================
      // Property "IsOpen"
      //===============================================================================================================


      [Description("IsOpen sets/resets the state of the valve"), Category("Common Valve Properties")]
      public bool IsOpen
      {
       get
       {
        return (bool)GetValue(IsOpenProperty);
       }
       set
       {
        SetValue(IsOpenProperty, value);
        if ((bool)value == true)
        {
         if (this.ImageValveOpen != null)
         {
          ImageBrush myImageBrush = new ImageBrush(this.ImageValveOpen);
          gridG1.Background = myImageBrush;
         }
        }
        else
        {
         if (this.ImageValveClosed != null)
         {
          ImageBrush myImageBrush = new ImageBrush(this.ImageValveClosed);
          gridG1.Background = myImageBrush;
         }
        }
       }
      }


      public static DependencyProperty IsOpenProperty
          = DependencyProperty.Register("IsOpen", typeof(bool), typeof(UC_Valve_Horizontal),
        new PropertyMetadata(true, IsOpenCallBack));

      public static void IsOpenCallBack(
          DependencyObject sender,
          DependencyPropertyChangedEventArgs e)
      {
       ((UC_Valve_Horizontal)sender).IsOpen = (bool)e.NewValue;
      }

    Jedes Ventil wird codemäßig durch eine Instanz der Klasse CValve präsentiert. Alle Ventile sind in einer Liste abgelegt.

    In dem "Code behind" des user controls machen wir für alle im  Window der Ventilanzeige angegebenen  user control UC_Valve_Horizontal dynamisch eine Datenbindung:

        foreach (CValve myValve in CValve.listValves)
        {
         if (myValve.sItemDesignation == _sItemDesignation)
         {
          clValve = myValve;
          // Bindung herstellen
          Binding myBinding = new Binding("boValue");
          myBinding.Source = clValve;
          myBinding.Mode = BindingMode.TwoWay;
          SetBinding(UC_Valve_Horizontal.IsOpenProperty, myBinding);
          return;
         }
        }

    Mit den boolschen Werten funktioniert das auch soweit ganz gut.

    Nun wollten wir aber anstatt der "boValu-Eigenschaft" vom Typ bool eine Enumeration der Ventilklasse binden, die weitere Zustände des Ventils definiert (also nicht nur auf/zu, sondern auch zB defekt, "nicht vorhanden", etc.), Dazu haben wir die Bindung folgerndermassen geändert:

        foreach (CValve myValve in CValve.listValves)
        {
         if (myValve.sItemDesignation == _sItemDesignation)
         {
          clValve = myValve;
          // Bindung herstellen
          Binding myBinding = new Binding("eState");
          myBinding.Source = clValve;
          myBinding.Mode = BindingMode.TwoWay;
          SetBinding(UC_Valve_Horizontal.IsOpenPropertyExt, myBinding);
          return;
         }
        }

     Mit  

    public class CValve : INotifyPropertyChanged

    {

    ........

       /// <summary>
      /// Aufzählung für den Zustand von Ventil
      /// </summary>
      public enum State : int
      {
       /// <summary>
       /// Zustand offen
       /// </summary>
       Open,
       /// <summary>
       /// Zustand geschlossen
       /// </summary>
       Closed,
       /// <summary>
       /// Zustand undefiniert
       /// </summary>
       Undef,
       /// <summary>
       /// Ventil nicht vorhanden
       /// </summary>
       None
      }

      /// <summary>
      /// Zustand - state
      /// </summary>

      State _eState;
      public State eState
      {
       get
       {

           return (_eState);  

        }
       set
       {
        _eState = value;
        OnPropertyChanged(new PropertyChangedEventArgs("eState"));
        NotifyPropertyChanged("eState");
       }
      }

     und in

     public partial class UC_Valve_Horizontal : UserControl
     {

    ........
      public static DependencyProperty IsOpenPropertyExt
          = DependencyProperty.Register("IsOpenExt", typeof(CValve.State), typeof(UC_Valve_Horizontal),
        new PropertyMetadata(CValve.State.Closed, IsOpenCallBackExt));

      public static void IsOpenCallBackExt(
          DependencyObject sender,
          DependencyPropertyChangedEventArgs e)
      {
       ((UC_Valve_Horizontal)sender).IsOpenExt = (CValve.State )e.NewValue;
      }

    .........

    }

    Leider funktioniert das nun nicht mehr ???????  Was machen wir falsch ??????

    Ich freue mich auf Eure Rückantworten.

    Gruß

    Gerhard

      

    Dienstag, 23. Oktober 2012 07:49

Antworten

  • Hallo Gerhard,

    Getter/Setter für DependencyProperties werden zur Laufzeit nicht aufgerufen,
    und so ist der Code im Setter für IsOpen wirkungslos.

    Da es sich anscheinend um eine visuelle Anpassung handelt, wäre es besser einen Converter zu verwenden. Ein Beispiel mit einer Ampel:
    http://www.switchonthecode.com/tutorials/wpf-tutorial-binding-converters

    Nebenbei: Ein einmaliges Aufrufen von PropertyChanged reicht und sollte nur stattfinden, wenn wirklich eine Änderung stattgefunden hat. Die Codefragmente sollten in etwa so aussehen:

       set	// Setter für eState
       {
            if (_eState != value)
            {
                _eState = value;
                NotifyPropertyChanged("eState");
            }
        }
        
    
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
                handler(this, e);
        }
    
        private void NotifyPropertyChanged(string propertyName)
        {
            this.OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
      

    Gruß Elmar

    Dienstag, 23. Oktober 2012 09:40
    Beantworter

Alle Antworten

  • Hallo Gerhard,

    "funktioniert nicht" ist leider keine Beschreibung, mit der man irgendwas anfangen könnte. Was genau funktioniert nicht? Ab wo in deinem Code geht es nicht mehr so, wie Du es erwarten würdest? Kommt eine Fehlermeldung und wenn ja, welche? (In dem Fall bitte die genaue und vollständige Meldung posten)


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Dienstag, 23. Oktober 2012 07:53
    Moderator
  • Hallo Gerhard,

    leider steht nicht, wie du bindest in der Oberfläche. Dein Code ist sehr vorbildlich ausführlich beschrieben, vermutlich liegt aber eher das Problem in der Oberflächenbindung. Allerdings könnte auch dein NotifyPropertyChanged Ereigniss falsch sein.

    In der Oberfläche verändere (du verwendest vermutlich WPF) verändere mitte einmal den Mode auf TwoWay (auch wenn eine Richtung noch nicht verwendet wird, kann man so erst mal sicher gehen).

    Hier Beispielhaft für eine Textbox

    <TextBox  Margin="2" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Text="{Binding UserName, Mode=TwoWay}" />

    Wenn dass nicht hilft, zeig mal bitte dein NotifyPropertyChanged Ereignis.


    Dienstag, 23. Oktober 2012 08:05
  • Sorry,

    dass ich mich zu ungenau ausgedrückt habe.

    Wenn sich der Zustand des Ventils ändert, wird  der Setter von eState noch durchlaufen und auch OnPropertyChanged und NotifyPropertyChanged von CValve:

      protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
      {
       if (PropertyChanged != null)
        PropertyChanged(this, e);
      }

      private void NotifyPropertyChanged(string propertyName)
      {
       if (PropertyChanged != null)
       {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
       }
      }

    PropertyChanged ist ungleich null. Soweit wäre m.E. alles okay.

    Im Anschluss daran müsste m.E. nun das DependencyProperty IsOpenPropertyExt aufgerufen werden. Hier kommt allerdings das System nie an, das Ventilbild ändert sich nicht.

    Gruß

    Gerhard

    Dienstag, 23. Oktober 2012 08:06
  • Hallo Gerhard,

    Getter/Setter für DependencyProperties werden zur Laufzeit nicht aufgerufen,
    und so ist der Code im Setter für IsOpen wirkungslos.

    Da es sich anscheinend um eine visuelle Anpassung handelt, wäre es besser einen Converter zu verwenden. Ein Beispiel mit einer Ampel:
    http://www.switchonthecode.com/tutorials/wpf-tutorial-binding-converters

    Nebenbei: Ein einmaliges Aufrufen von PropertyChanged reicht und sollte nur stattfinden, wenn wirklich eine Änderung stattgefunden hat. Die Codefragmente sollten in etwa so aussehen:

       set	// Setter für eState
       {
            if (_eState != value)
            {
                _eState = value;
                NotifyPropertyChanged("eState");
            }
        }
        
    
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            var handler = this.PropertyChanged;
            if (handler != null)
                handler(this, e);
        }
    
        private void NotifyPropertyChanged(string propertyName)
        {
            this.OnPropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
      

    Gruß Elmar

    Dienstag, 23. Oktober 2012 09:40
    Beantworter
  • Hallo Gerhard Fischer,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT   Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Donnerstag, 6. Dezember 2012 15:38
    Moderator