【发布时间】:2020-08-11 07:57:39
【问题描述】:
我试图弄清楚如何从 MainWindow.xaml.cs 订阅在 ViewModel 中触发的事件。
视图模型:
public class LoginViewModel : INotifyPropertyChanged
{
private bool isAuthenticatedUser;
public bool IsAuthenticatedUser
{
get { return isAuthenticatedUser; }
set
{
Debug.WriteLine("Old value:" + isAuthenticatedUser);
isAuthenticatedUser = value;
Debug.WriteLine("New value:" + isAuthenticatedUser);
OnNotifyPropertyChanged("IsAuthenticatedUser");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnNotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
Debug.WriteLine($"Property Change on LoginView.IsAuthenticatedUser");
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MainWindow.xaml.cs
public partial class MainWindow
{
private int? oldUnreadTextsCount = 0;
public MainWindow()
{
DataContext = new MainWindowViewModel();
InitializeComponent();
InitializeTimer();
Loaded += MainWindow_Loaded;
}
public TextsViewModel TextsViewModel { get; set; }
public LoginViewModel LoginViewModel { get; set; }
public MainWindowViewModel MainWindowViewModel { get; set; }
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
LoginViewModel = new LoginViewModel();
// First Subscribe;
LoginViewModel.PropertyChanged += UserAuthentication_PropertyChange;
// Second Fire Change / Fire update on UserAuthentication_PropertyChange.
LoginViewModel.TestAuthentication();
// Third Change Views appropriately
if (LoginViewModel.IsAuthenticatedUser)
{
NavigationFrame.NavigationService.Navigate(new HomeView());
TextsViewModel = new TextsViewModel();
TextsViewModel.PropertyChanged += UnreadTexts_PropertyChanged;
}
else
{
NavigationFrame.NavigationService.Navigate(new LoginView());
}
}
private void UserAuthentication_PropertyChange(object sender, PropertyChangedEventArgs e)
{
Debug.WriteLine("PROPERTY CHANGE REGISTERED:MainWindow:Checking if logged in.");
if (LoginViewModel.IsAuthenticatedUser)
{
Header.Visibility = Visibility.Visible;
Footer.Visibility = Visibility.Visible;
Debug.WriteLine("Logged In");
}
else
{
Header.Visibility = Visibility.Hidden;
Footer.Visibility = Visibility.Hidden;
Debug.WriteLine("Logged Out");
}
}
}
看来我需要做的就是在我的通知类(ViewModel)中:
实现
INotifyPropertyChanged添加
public event PropertyChangedEventHandler PropertyChanged;添加
OnNotifyPropertyChanged("IsAuthenticatedUser");将以下方法添加到我的通知类中:
protected void OnNotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
Debug.WriteLine($"Property Change on LoginView.IsAuthenticatedUser");
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
然后在我的 SUBSCRIBING 类(MainViewWindow)中添加以下内容:
- 订阅我的 ViewModel 中的事件
LoginViewModel.PropertyChanged += UserAuthentication_PropertyChange; - 添加订阅中引用的方法,如下所示
private void UserAuthentication_PropertyChange(object sender, PropertyChangedEventArgs e)
{
Debug.WriteLine("PROPERTY CHANGE REGISTERED:MainWindow:Checking if logged in.");
if (LoginViewModel.IsAuthenticatedUser)
{
Header.Visibility = Visibility.Visible;
Footer.Visibility = Visibility.Visible;
Debug.WriteLine("Logged In");
}
else
{
Header.Visibility = Visibility.Hidden;
Footer.Visibility = Visibility.Hidden;
Debug.WriteLine("Logged Out");
}
}
不幸的是,这似乎不起作用。订阅的方法 UserAuthentication_PropertyChange 仅在应用程序首次启动并且 ViewModel 上的 IsAuthenticatedUser 属性值发生变化时触发一次。为什么每次发生变化时都不起作用?
有关更多信息,如果您能帮助我(对我而言)理解这种现象,这里是应用程序运行时打印到控制台的内容的简要说明,我触发登录和注销序列。
启动应用程序 - 当前已注销。
TestAuthentication:LoginViewModel:False
Old value:False
New value:False
Property Change on LoginView.IsAuthenticatedUser
PROPERTY CHANGE REGISTERED:MainWindow:Checking if logged in.
Logged Out
耶!它看起来像它的工作......但是等等 - 还有更多......
然后我登录
AuthenticateUser:LoginViewModel:True
Old value:False
New value:True
Property Change on LoginView.IsAuthenticatedUser
属性更改已触发,但 MainWindow 不再听到它...为什么不呢?
【问题讨论】:
-
您是如何实际登录的?我看到
DataContext是MainWindowViewModel。那么如何触发LoginViewModel的登录逻辑。现在,您似乎正在对LoginViewModel的两个实例进行操作。您只收听您在Loaded处理程序中创建的实例的事件,但是当您登录时,您使用的是另一个可能是LoginViewModel的 XAML 实例? -
是的,没错,当我使用
NavigationFrame.NavigationService.Navigate(new LoginView());创建登录页面时,我在该页面的codeBehind 中实例化了一个新的LoginViewModel。是否有 2 个这样的实例导致问题? -
是的,这就是我要说的。您只订阅了一个实例的
PropertyChanged。此实例与您用于通过登录页面进行真实登录的实例不同。另一个副作用是两个视图模型具有不同的状态。如果IsAuthenticatedUser在一个实例中是true,那么在另一个实例中它仍然是false。你绝对不想要这个。确保您只使用每个视图模型的一个实例,除非您故意想要拥有多个实例 - 但在这种情况下,您需要一个共享/重用实例。 -
嗯。这很有意义,而且我以前没有考虑过。状态显然会从一个实例变为另一个实例。你会如何推荐分享我的 ViewModel?在这种情况下我可以注入这个 ViewModel 并且可能没问题,但其他情况呢?有没有办法让 ViewModel 的每个实例都可以全局访问?例如,我可以将
LoginViewModel实例传递到我的导航方法中,因为这是我真正需要访问它的唯一地方——但这并不总是正确的。我需要让我的TextViewModel可以在多个地方访问。 -
您也可以将其作为答案,以便我接受。我已经测试过了,你解决了这个问题!!!非常感谢您帮助我理解这一点!!!
标签: c# wpf events inotifypropertychanged