所以我有一个使用MVVM模式的WPF应用程序,它使用MVVM Light库。 对于INotifyPropertyChanged我正在使用到目前为止运作良好的Fody.Weavers库。
我有一个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;
}
}
}
然而,当我在SelectedViewModel上调用CheckAccess方法时,直接从MainViewModel更改CanAccessTestButton属性,或者使用MainViewModels AdminLogin方法中的新HomeViewModel设置SelectedViewModel,它们会在我单步执行代码时看到更新,但是绑定不更新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 Light有一个ViewModelLocator.cs类,您需要在其中声明每个ViewModel:
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
}
}
然后在每个视图中,引用要绑定到的视图模型(简化标记为简洁)
MainWindow.xaml:
<Window DataContext="{Binding Main, Source={StaticResource Locator}}">
Home.xaml:
<UserControl DataContext="{Binding Home, Source={StaticResource Locator}}">
启动时,HomeViewModel构造函数将首先从ViewModelLocator.cs调用两次,然后再从MainViewModel.cs调用。也许ViewModelLocator具有对我在屏幕上看到的视图的引用。关于如何实现我希望实现的目标的任何想法?
答案 0 :(得分:4)
我注意到
HomeViewModel
构造函数从ViewModelLocator
调用一次,然后在设置MainViewModel
绑定时再次在Content
内调用
那是你的问题。您正在创建视图模型的另一个实例并绑定到该实例。
从DataContext
中的UserControl
删除Home.xaml
属性:
<UserControl DataContext="{Binding Home, Source={StaticResource Locator}}">
您希望绑定到您自己创建的HomeViewModel
实例,而不是视图模型定位器为您创建的实例。所以这里你不需要任何视图模型定位器。