2017-05-31 3 views
1

So habe ich eine WPF-App mit dem MVVM-Muster, das die MVVM Light-Bibliothek verwendet. Für INotifyPropertyChanged verwende ich die Fody.Weavers-Bibliothek, die bisher gut funktioniert.WPF MVVM Child ViewModel Eigenschaften nicht aktualisieren Ansicht

Ich habe eine MainWindow.xaml, die ein ContentControl hat, ihre Content-Eigenschaft ist an eine Eigenschaft in seinem Ansichtsmodell für die Navigation gebunden. Das funktioniert auch gut.

MainWindow.xaml:

<ContentControl Content="{Binding SelectedViewModel}"></ContentControl> 

MainViewModel.cs

public class MainViewModel : ViewModelBase 
{ 
    // Note that Fody library handles INotifyPropertyChanged 
    public event PropertyChangedEventHandler PropertyChanged; 
    public object SelectedViewModel { get; set; } 

    public MainViewModel() 
    { 
     SelectedViewModel = new HomeViewModel(); 
    } 

    public RelayCommand<PasswordBox> AdminLoginCommand => new RelayCommand<PasswordBox>(AdminLogin); 

    private void AdminLogin(PasswordBox passwordBox) 
    { 
     // Login Logic... 

     // Does not work 
     SelectedViewModel = new HomeViewModel(); 

     // Does not work either 
     if (SelectedViewModel is HomeViewModel) 
     { 
      ((HomeViewModel)SelectedViewModel).CheckAccess(); 
     } 

     // Does not work either 
     if (SelectedViewModel is HomeViewModel) 
     { 
      ((HomeViewModel)SelectedViewModel).CanAccessTestButton = true; 
     } 
    } 
} 

Allerdings, wenn ich die Checkaccess-Methode auf dem SelectedViewModel nennen, direkt die CanAccessTestButton Eigenschaft von MainViewModel ändern oder setzen SelectedViewModel mit einem neuen HomeViewModel von MainViewModels AdminLogin-Methode, sie werden aktualisiert, wie ich sehe, wenn ich durch den Code gehe, aber die Bindung aktualisiert die Benutzeroberfläche nicht. Ich habe diese Methoden selbstständig ausprobiert.

Ich denke, Home.xaml nicht auf die Eigenschaft abholen, wenn vom übergeordneten Ansichtsmodell geändert. Wenn der Konstruktor von HomeViewModel beim ersten Laden initialisiert wird und sich korrekt an den Wert von CanAccessTestButton bindet, scheinen alle anderen Aufrufe von MainViewModel die Ansicht nicht zu aktualisieren.

Lustig genug, wenn ich versuche, die Eigenschaft aus dem HomeViewModel mit einem RelayCommand gebunden an eine andere Schaltfläche in Home.xaml zu ändern, funktioniert es gut.

Wie kann ich es vom Elternteil arbeiten lassen?

Home.xaml:

<Button Content="Test" IsEnabled="{Binding CanAccessTestButton}"/> 

HomeViewModel.cs:

public class HomeViewModel : ViewModelBase 
    { 
     // Note that Fody library handles INotifyPropertyChanged    
     public event PropertyChangedEventHandler PropertyChanged; 
     public bool CanAccessTestButton { get; set; } 

     public HomeViewModel() 
     { 
      OtherButtonCommand = new RelayCommand(OtherButtonClick); 
      CheckAccess(); 
     } 

     public RelayCommand OtherButtonCommand { get; set; } 
     private void OtherButtonClick() 
     { 
      // WORKS!!! 
      CheckAccess() 
     } 

     public void CheckAccess() 
     { 
      CanAccessTestButton = AppContext.Instance.LoggedInUserHasAccess(); 
     } 
    } 

Edit: MVVM Licht hat eine ViewModelLocator.cs Klasse, die Sie jedes Ansichtsmodell in deklarieren müssen:

public class ViewModelLocator 
    { 
     public ViewModelLocator() 
     { 
      ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); 

      SimpleIoc.Default.Register<MainViewModel>(); 
      SimpleIoc.Default.Register<HomeViewModel>(); 
     } 

     public MainViewModel Main => ServiceLocator.Current.GetInstance<MainViewModel>(); 

     public HomeViewModel Home => ServiceLocator.Current.GetInstance<HomeViewModel>(); 

     public static void Cleanup() 
     { 
      // TODO Clear the ViewModels 
     } 
    } 

Dann in jedem Vie w verweisen Sie auf die Ansicht Modell, das Sie in (der Kürze halber vereinfacht Markup) binden möchten

MainWindow.xaml:

<Window DataContext="{Binding Main, Source={StaticResource Locator}}"> 

Home.xaml:

<UserControl DataContext="{Binding Home, Source={StaticResource Locator}}"> 

Beim Start HomeViewModel Konstruktor wird zweimal aufgerufen, zuerst von ViewModelLocator.cs, dann erneut von MainViewModel.cs. Vielleicht hat der ViewModelLocator den Verweis auf die Ansicht, die ich auf dem Bildschirm sehe. Irgendwelche Ideen, um zu erreichen, was ich erreichen möchte?

+1

Sie werden nie ein PropertyChanged-Ereignis auslösen – Fabiano

+1

Fody.Weavers behandelt dies im Hintergrund. –

+0

Wie viele Instanzen des HomeViewModel werden erstellt? – mm8

Antwort

3

Ich bemerkte die HomeViewModel Konstruktor einmal von ViewModelLocator, innerhalb MainViewModel dann wieder aufgerufen wird, wenn die Content Bindung

, dass Ihr Problem ist gesetzt.Sie erstellen eine weitere Instanz des Ansichtsmodells und binden an diese.

Entfernen Sie die DataContext Attribut aus dem UserControl in Home.xaml:

<UserControl DataContext="{Binding Home, Source={StaticResource Locator}}"> 

Sie möchten die HomeViewModel Instanz binden, die Sie selbst erstellen, nicht derjenige, der View-Modell-Locator für Sie erstellt. Sie brauchen hier also keinen View Model Locator.

+0

Es hat funktioniert! Fantastisch! Ich weiß zwar nicht, wie HomeViewModel jetzt an Home.xaml bindet. Aber es funktioniert trotzdem. Danke :-) –

+0

Erbt den DataContext vom ContentControl. – mm8

+0

Ja, aber DataContext von ContentControl ist auf HomeViewModel eingestellt, woher weiß es, dass Home.xaml seine Ansicht ist? Ich habe ungefähr 10 andere Ansichten und sehe Modelle auch an. –

Verwandte Themen