none
Binding an eine DependencyProperty in einem UserControl aus einem Child-UserControl funktioniert nicht RRS feed

  • Frage

  • Hallo zusammen,

    ich habe in einem UserControl eine bool-DependencyProperty angelegt. Diese habe ich an die Property eines ViewModels gebunden:

    public partial class RibbonBackstage : UserControl, INotifyPropertyChanged
        {
         public static DependencyProperty IsAdminProperty = DependencyProperty.Register("IsAdmin", typeof(bool), typeof(RibbonBackstage));
    
            public bool IsAdmin
            {
                get { return (bool)GetValue(IsAdminProperty); }
                set
                {
                    SetValue(IsAdminProperty, value);
                    this.OnPropertyChanged("IsAdmin");
                }
            }
    
            public RibbonBackstage()
            {
                InitializeComponent();
                IsAdmin = BenutzerAngemeldetViewModel.Instance.Admin;
                ...
            }

    In diesem Usercontrol werden weitere Child-UserControls verwendet:

    <UserControl x:Class="Test.RibbonBackstage"
                 xmlns:Fluent="clr-namespace:Fluent;assembly=Fluent"
                 ...
                 x:Name="RibbonBackstageView">
    
      <Grid>
         ...
         <Fluent:BackstageTabControl>
    
                    <Fluent:BackstageTabItem Header="Übersicht">
                        <Fluent:BackstageTabItem.ContentTemplate>
                            <DataTemplate>
                                <controls:BackstageUebersicht />
                            </DataTemplate>
                        </Fluent:BackstageTabItem.ContentTemplate>
                    </Fluent:BackstageTabItem>
    
                    <Fluent:SeparatorTabItem />
    
                    <Fluent:BackstageTabItem Header="Verwaltung">
                        <Fluent:BackstageTabItem.ContentTemplate>
                            <DataTemplate>
                                <controls:BackstageVerwaltung />
                            </DataTemplate>
                        </Fluent:BackstageTabItem.ContentTemplate>
                        
                    </Fluent:BackstageTabItem>
    
                    <Fluent:SeparatorTabItem />
    
                    <Fluent:BackstageTabItem Header="Administration" 
                                             x:Name="tabAdmin"
                                             Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}, Mode=FindAncestor}, Path=IsAdmin, 
                                                                  Converter={StaticResource boolToVisibleOrCollapsed}, 
                                                                  Mode=TwoWay, 
                                                                  UpdateSourceTrigger=PropertyChanged}">
                        <Fluent:BackstageTabItem.ContentTemplate>
                            <DataTemplate>
                                <controls:BackstageAdmin />
                            </DataTemplate>
                        </Fluent:BackstageTabItem.ContentTemplate>
          ...
      </Grid>
    </UserControl>

    Im Child-UserControl "BackstageUebersicht" kann ich die Property "Admin" verändern.
    Nachdem diese geändert wurde und das Update-Event ausgeführt wurde, damit der Wert der Property aus dem ViewModel "BenutzerAngemeldetViewModel" in die Datenbank gespeichert wird, wird jedoch die DependencyProperty "IsAdmin" nicht geändert, obwohl der UpdateSourceTrigger=PropertyChanged gesetzt ist!!!

    Was läuft da schief???

    Gruß Jürgen

    Freitag, 22. April 2016 14:29

Antworten

  • Hallo Tom,

    du hast Recht, ich habe viel zu kompliziert gedacht, ich brauche gar keine DependencyProperty!

    Die Lösung ist ganz einfach mit MVVM :-)

    Ich habe im ViewModel "BenutzerAngemeldetViewModel" eine Property "Admin". Dieses ViewModel wird bei der Anmeldung instanziert.

    Also habe ich den DataContext im Loading des UserControls auf diese Instanz des ViewModels gesetzt:
    benutzerViewModel = BenutzerAngemeldetViewModel.Instance;
    this.DataContext = benutzerViewModel;

    und im XAML einfach die Property
    "Visibility={Binding Admin...}" an die ViewModel-Property "Admin" gebunden.

    Und es funktionöckelt perfekt!!! :-)

    Gruß und noch schönes WE

    Jürgen

    P.s.:
    Langsam fange ich an, MVVM richtig zu verstehen und zu mögen, denn das ist genau das, um mit WPF richtig arbeiten zu können.

    • Als Antwort markiert Jürgen Sch Samstag, 23. April 2016 08:30
    Samstag, 23. April 2016 08:29

Alle Antworten

  • Hallo Jürgen,

    zunächst 2 Dinge abseits deines Problems:

    1. Im Konstruktor von RibbonBackstage greifst du auf ein ViewModel zu was praktisch die Verwendung von MVVM hinfällig macht. Die Eigenschaft IsAdmin sollte von außen gebunden werden. Damit wird die Zuweisung des (scheinbaren) Standardwerts überflüssig.
    2. Das Auslösen des PropertyChanged-Events im Setter der IsAdmin-Eigenschaft kannst du dir auch sparen, da Getter und Setter von der WPF Runtime nicht genutzt werden. Diese greifen direkt auf die Get/SetValue-Methoden zurück. Wenn du unbedingt ein Event dieser Art brauchst (eigentlich nicht notwendig bei DPs) solltest du die PropertyMetadata in der Register-Methode angeben und dort einen Changed-Eventhandler mit übergeben.

    Das eigentliche Problem das sich dir hier stellt ist das ich keine Bindung zwischen IsAdmin-Eigenschaft deines UserControls und dem ViewModel sehen kann. Du weißt zwar die Eigenschaft IsAdmin zu (vgl. 1.), bindest diese aber nicht. Bindungen müssen entweder über XAML mittels {Binding ...} (bzw. ausführlich mit Tags) oder im Code mittels SetBinding erfolgen. Letzteres ist nicht zu empfehlen wenn du MVVM nutzen willst.

    Wie schon unter 1. gesagt solltets du die IsAdmin-Eigenschaft von außerhalb des Controls binden. Eben dort wo das Control auch genutzt wird.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Freitag, 22. April 2016 15:20
    Moderator
  • Hallo Tom,

    du hast Recht, ich habe viel zu kompliziert gedacht, ich brauche gar keine DependencyProperty!

    Die Lösung ist ganz einfach mit MVVM :-)

    Ich habe im ViewModel "BenutzerAngemeldetViewModel" eine Property "Admin". Dieses ViewModel wird bei der Anmeldung instanziert.

    Also habe ich den DataContext im Loading des UserControls auf diese Instanz des ViewModels gesetzt:
    benutzerViewModel = BenutzerAngemeldetViewModel.Instance;
    this.DataContext = benutzerViewModel;

    und im XAML einfach die Property
    "Visibility={Binding Admin...}" an die ViewModel-Property "Admin" gebunden.

    Und es funktionöckelt perfekt!!! :-)

    Gruß und noch schönes WE

    Jürgen

    P.s.:
    Langsam fange ich an, MVVM richtig zu verstehen und zu mögen, denn das ist genau das, um mit WPF richtig arbeiten zu können.

    • Als Antwort markiert Jürgen Sch Samstag, 23. April 2016 08:30
    Samstag, 23. April 2016 08:29