В данный момент похоже, что вы работаете с двумя экземплярами LoginViewModel. Вы слушаете только события экземпляра, который вы создали в обработчике Loaded, но при входе в систему вы используете другой, возможно, XAML-экземпляр LoginViewModel.
Чтобы ответить на ваш вопрос, как работать с моделями представления, я предлагаем заменить Frame
на ContentControl
.
. Для этого требуется, чтобы у каждого представления была своя собственная модель представления, например, LoginViewModel -> LoginView, HomeViewModel -> HomeView. Кроме того, каждое представление должно быть определено внутри DataTemplate
.
A ContentControl
, привязываемого к свойству SelectedPage
и отображающего страницу, применяя соответствующий DataTemplate
.
. Навигация теперь происходит внутри просмотреть модель, установив SelectedPage
свойство MainWindowViewModel
для модели представления страницы, к которой вы будете sh переходить.
Таким образом вы можете перемещать навигацию к модели представления и удобно обрабатывать события и т. д. c, поскольку модель представления знает о других моделях представления при использовании композиции (или агрегации).
PageName.cs
Перечисление для исключения строк magi c как страницы идентификаторы в XAML и C#.
Может использоваться как CommandParameter
при использовании, например, с Button.Command
для перехода к определенной странице.
enum PageName
{
LoginView, HomeView
}
MainWindowViewModel.cs
public class MainWindowViewModel : INotifyPropertyChanged
{
public TextViewModel TextViewModel { get; set; }
private Dictionary<PageName, object> Pages { get; set; }
private object selectedPage;
public object SelectedPage
{
get => this.selectedPage;
set
{
this.selectedPage = value;
OnPropertyChanged();
}
}
private bool isAuthenticated;
public bool IsAuthenticated
{
get => this.isAuthenticated;
set
{
this.isAuthenticated = value;
OnPropertyChanged();
}
}
public MainWindowViewModel()
{
// Alternatively use constructor injection
var loginPageViewModel = new LoginViewModel();
loginPageViewModel.AuthenticationStatusChanged += OnAuthenticationStatusChanged;
this.Pages = new Dictionary<PageName, object>()
{
{ PageName.LoginView, loginPageViewModel },
{ PageName.HomeView, new HomeViewModel() }
}
// Show login screen initially
this.SelectedPage = Pages[PageName.LoginView];
this.TextViewModel = new TextViewModel();
}
// Example ICommand execute action, triggered e.g. on Button.Command,
// where the CommandParameter is a value of the PageName enumeration
private void ExecuteNavigateToPage(object commandParameter)
{
if (commandParameter is PageName pageName
&& this.Pages.TryGetValue(pageName, out object pageViewModel)
{
this.SelectedPage = pageViewModel;
}
}
private void OnAuthenticationStatusChanged(object sender, EventArgs e)
{
this.IsAuthenticated = (sender as LoginViewModel).IsAuthenticatedUser;
// Redirect to main page when user has authenticated successfully
if (this.IsAuthenticated)
{
this.SelectedPage = Pages[PageName.HomeView];
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
LoginViewModel.cs
public class LoginViewModel : INotifyPropertyChanged
{
public event EventHandler AuthenticationStatusChanged;
public event PropertyChangedEventHandler PropertyChanged;
private bool isAuthenticatedUser;
public bool IsAuthenticatedUser
{
get => this.isAuthenticatedUser;
set
{
this.isAuthenticatedUser = value;
OnPropertyChanged();
OnAuthenticationStatusChanged();
}
}
private void OnAuthenticationStatusChanged()
{
this.AuthenticationStatusChanged?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
** MainWindow.xaml.cs **
public partial class MainWindow
{
private int? oldUnreadTextsCount = 0;
public MainWindow()
{
InitializeComponent();
InitializeTimer();
var mainWindowViewModel = new MainWindowViewModel();
DataContext = mainWindowViewModel;
mainWindowViewModel.TextsViewModel.PropertyChanged += UnreadTexts_PropertyChanged;
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
// Navigation (and debugger output) has been moved to the MainWindowViewModel.
// Toggling of the visibility has been moved to XAML using DataTrigger
}
}
LoginView .xaml
<UserControl x:Class="LoginView">
<!--
DataContext is automatically the LoginViewModel,
accessible from code-behind via the DataContext property
-->
<TextBlock Text="{Binding IsAuthenticatedUser}" />
</UserControl>
HomeView.xaml
<UserControl x:Class="LoginView">
<!--
DataContext is automatically the HomeViewModel,
accessible from code-behind via the DataContext property
-->
<TextBlock Text="Welcome back user!" />
</UserControl>
MainW indow.xaml
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type LoginViewModel}">
<LoginView />
</DataTemplate>
<DataTemplate DataType="{x:Type HomeViewModel}">
<HomeView />
</DataTemplate>
</Window.Resources>
<StackPanel>
<TextBlock x:Name="Header">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsAuthenticated}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock>
</TextBlock>
<!--
Page host. Setting the content to a page view model,
will automatically load the corresponding DataTemplate
-->
<ContentControl Content="{Binding SelectedPage}" />
<TextBlock x:Name="Footer">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsAuthenticated}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock>
</TextBlock>
</Window>