2017-05-31 143 views
1

所以我有一個WPF應用程序利用MVVM模式,它使用MVVM光庫。 對於INotifyPropertyChanged我正在使用目前運行良好的Fody.Weavers庫。WPF MVVM兒童ViewModel屬性不更新視圖

我有一個MainWindow.xaml有一個ContentControl,它的Content屬性綁定到它的視圖模型上的一個屬性進行導航。這也適用。

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; 
     } 
    } 
} 

然而,當我調用checkAccess方法上SelectedViewModel,直接CanAccessTestButton財產MainViewModel改變,或者設置SelectedViewModel用新HomeViewModel AdminLogin方法中的HomeViewModel,它們會在我逐步瀏覽代碼時看到更新,但綁定不會更新UI。我已經獨立嘗試過這些方法。

我覺得Home.xaml在從父視圖模型更改時沒有選擇屬性。當首次加載初始化HomeViewModel的構造函數時,它將正確綁定到CanAccessTestButton設置的任何位置,而來自MainViewModel的任何其他調用似乎都不會更新該視圖。

有趣的是,當我嘗試使用綁定到Home.xaml中另一個按鈕的RelayCommand來更改HomeViewModel中的屬性時,它工作正常。

我怎樣才能從父母工作?

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(); 
     } 
    } 

編輯: MVVM光有您需要聲明每個視圖模型在ViewModelLocator.cs類:

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 
     } 
    } 

然後在每個Vie W,您引用您要綁定的視圖模型中(標記簡化了簡潔)

MainWindow.xaml:

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

Home.xaml:

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

在啓動時,HomeViewModel構造首先從ViewModelLocator.cs中調用兩次,然後再從MainViewModel.cs中調用。也許ViewModelLocator具有對我在屏幕上看到的視圖的引用。關於如何完成我想實現的任何想法?

+1

你永遠不會引發PropertyChanged事件 – Fabiano

+1

Fody.Weavers在後臺處理這個事件。 –

+0

創建多少個HomeViewModel實例? – mm8

回答

3

我注意到當Content綁定設置

那是你的問題的HomeViewModel構造函數將被從ViewModelLocator調用一次,然後再次內MainViewModel。您正在創建視圖模型的另一個實例並綁定到這個實例。

Home.xaml取下UserControlDataContext屬性:

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

你希望綁定到自己創建的HomeViewModel實例,而不是該視圖模型定位器爲您創建一個。所以你不需要任何視圖模型定位器。

+0

它工作!太棒了!雖然我不知道HomeViewModel如何與Home.xaml綁定。但它仍然有效。謝謝:-) –

+0

它從ContentControl繼承DataContext。 – mm8

+0

是的,但ContentControl的DataContext被設置爲HomeViewModel,它怎麼知道Home.xaml是它的視圖?我也有大約10個其他視圖和視圖模型。 –