从另一个 ViewModel 调用函数
Call a function from another ViewModel
我是这门语言的初学者,正在努力学习更多关于最佳实践以及如何做得更好的方法...
我有这个 repo 作为示例应用程序:https://github.com/Albvadi/NavigationMVVM
如果你运行它,一切正常。您可以导航到其他视图并增加在所有视图中共享的计数器。
但是,如果您在第 24 行取消注释 MainViewModel.cs
文件中的 ActualView
分配并将登录视图放在 InitialView
前面,我不知道如何重定向用户登录成功后Initialview
。
当登录正确时,我将用户数据填充到 ManagerData 中,所有这些我都需要调用 MainViewModel
中的函数以将用户重定向到初始视图。我怎样才能从 LoginViewModel
调用另一个 MainViewModel
而不是从视图调用?
更新:添加相关代码
App.xaml
<Application
x:Class="NavigationMVVM.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NavigationMVVM"
xmlns:Views="clr-namespace:NavigationMVVM.Views"
xmlns:ViewModels="clr-namespace:NavigationMVVM.ViewModels"
StartupUri="MainWindow.xaml">
<Application.Resources>
<DataTemplate
DataType="{x:Type ViewModels:MainViewModel}">
<local:MainWindow />
</DataTemplate>
<DataTemplate
DataType="{x:Type ViewModels:LoginViewModel}">
<Views:Login />
</DataTemplate>
<DataTemplate
DataType="{x:Type ViewModels:InitialViewModel}">
<Views:Initial />
</DataTemplate>
<DataTemplate
DataType="{x:Type ViewModels:FirstViewModel}">
<Views:First />
</DataTemplate>
<DataTemplate
DataType="{x:Type ViewModels:SecondViewModel}">
<Views:Second />
</DataTemplate>
</Application.Resources>
</Application>
MainWindow.xaml
<Window
x:Class="NavigationMVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NavigationMVVM"
xmlns:viewModels="clr-namespace:NavigationMVVM.ViewModels"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="MainWindow"
Height="450"
Width="800">
<Window.DataContext>
<viewModels:MainViewModel />
</Window.DataContext>
<Grid>
<ContentControl
Content="{Binding ActualView}" />
</Grid>
</Window>
BaseViewModel.cs
using System.ComponentModel;
namespace NavigationMVVM.Common
{
public class BaseViewModel : INotifyPropertyChanged
{
private BaseViewModel _ActualView;
public BaseViewModel ActualView
{
get => _ActualView;
set
{
_ActualView = value;
RaisePropertyChanged(null);
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
#endregion
}
}
MainViewModel.cs
using NavigationMVVM.Common;
using NavigationMVVM.Models;
using System.Windows.Input;
namespace NavigationMVVM.ViewModels
{
public class MainViewModel : BaseViewModel
{
public DataManager SharedData = new DataManager();
public InitialViewModel InitialVM;
public FirstViewModel FirstVM;
public SecondViewModel SecondVM;
public LoginViewModel LoginVM;
public MainViewModel()
{
LoginVM = new LoginViewModel(SharedData);
InitialVM = new InitialViewModel(SharedData);
FirstVM = new FirstViewModel(SharedData);
SecondVM = new SecondViewModel(SharedData);
ActualView = InitialVM;
//ActualView = LoginVM;
}
public ICommand DisplayFirstView
{
get
{
return new RelayCommand(action => ActualView = FirstVM,
canExecute => true);
}
}
public ICommand DisplaySecondView
{
get
{
return new RelayCommand(action => ActualView = SecondVM,
canExecute => true);
}
}
public ICommand DisplayInitialView
{
get
{
return new RelayCommand(action => ActualView = InitialVM,
canExecute => true);
}
}
}
}
LoginViewModel.cs
using NavigationMVVM.Common;
using NavigationMVVM.Models;
using System.Diagnostics;
using System.Windows.Input;
namespace NavigationMVVM.ViewModels
{
public class LoginViewModel : BaseViewModel
{
private DataManager _DataManager;
public ICommand LoginCmd;
public RelayCommand DoLoginCmd { get; }
private string _Username;
public string Username
{
get => _Username;
set
{
_Username = value;
RaisePropertyChanged(null);
}
}
private string _Password;
public string Password
{
get => _Password;
set
{
_Password = value;
RaisePropertyChanged(null);
}
}
private string _MessageInfo;
public string MessageInfo
{
get => _MessageInfo;
set
{
_MessageInfo = value;
RaisePropertyChanged(null);
}
}
public LoginViewModel(DataManager sharedData)
{
_DataManager = sharedData;
DoLoginCmd = new RelayCommand(param => DoLogin(), canExec => (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password)));
}
public void DoLogin()
{
if (Username == "admin" && Password == "password")
{
_DataManager.User.Name = "Administrator";
_DataManager.User.Mail = "admin@company.com";
MessageInfo = "Login OK!... How to redirect??";
}
else
{
MessageInfo = "Username or Password incorrect!";
}
}
}
}
谢谢。
有多种方法可以完成您想要的。我将 post 在 MVVM 模式中工作时非常常见的两种方法
基于事件的方法:
public MainViewModel()
{
LoginVM = new LoginViewModel(SharedData);
LoginVM.PropertyChanged += LoginVM_PropertyChanged;
InitialVM = new InitialViewModel(SharedData);
FirstVM = new FirstViewModel(SharedData);
SecondVM = new SecondViewModel(SharedData);
//ActualView = InitialVM;
ActualView = LoginVM;
}
private void LoginVM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if(sender.GetType() == typeof(LoginViewModel) && e.PropertyName == "MessageInfo")
{
var loginVM = (LoginViewModel)sender;
if (loginVM.MessageInfo == "OK")
{
ActualView = InitialVM;
}
}
}
Cunstructor 注入:
private Action _loginAction;
public LoginViewModel(DataManager sharedData, Action loginAction )
{
_DataManager = sharedData;
DoLoginCmd = new RelayCommand(param => DoLogin(), canExec => (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password)));
_loginAction = loginAction;
}
public void DoLogin()
{
if (Username == "admin" && Password == "password")
{
_DataManager.User.Name = "Administrator";
_DataManager.User.Mail = "admin@company.com";
MessageInfo = "Login OK!... How to redirect??";
_loginAction.Invoke();
}
else
{
MessageInfo = "Username or Password incorrect!";
}
}
和
public MainViewModel()
{
LoginVM = new LoginViewModel(SharedData, () => ActualView = InitialVM);
InitialVM = new InitialViewModel(SharedData);
FirstVM = new FirstViewModel(SharedData);
SecondVM = new SecondViewModel(SharedData);
//ActualView = InitialVM;
ActualView = LoginVM;
}
旁注:在 BaseViewModel 上放置 属性“ActualView”是一个相当奇怪的选择
我是这门语言的初学者,正在努力学习更多关于最佳实践以及如何做得更好的方法...
我有这个 repo 作为示例应用程序:https://github.com/Albvadi/NavigationMVVM
如果你运行它,一切正常。您可以导航到其他视图并增加在所有视图中共享的计数器。
但是,如果您在第 24 行取消注释 MainViewModel.cs
文件中的 ActualView
分配并将登录视图放在 InitialView
前面,我不知道如何重定向用户登录成功后Initialview
。
当登录正确时,我将用户数据填充到 ManagerData 中,所有这些我都需要调用 MainViewModel
中的函数以将用户重定向到初始视图。我怎样才能从 LoginViewModel
调用另一个 MainViewModel
而不是从视图调用?
更新:添加相关代码
App.xaml
<Application
x:Class="NavigationMVVM.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NavigationMVVM"
xmlns:Views="clr-namespace:NavigationMVVM.Views"
xmlns:ViewModels="clr-namespace:NavigationMVVM.ViewModels"
StartupUri="MainWindow.xaml">
<Application.Resources>
<DataTemplate
DataType="{x:Type ViewModels:MainViewModel}">
<local:MainWindow />
</DataTemplate>
<DataTemplate
DataType="{x:Type ViewModels:LoginViewModel}">
<Views:Login />
</DataTemplate>
<DataTemplate
DataType="{x:Type ViewModels:InitialViewModel}">
<Views:Initial />
</DataTemplate>
<DataTemplate
DataType="{x:Type ViewModels:FirstViewModel}">
<Views:First />
</DataTemplate>
<DataTemplate
DataType="{x:Type ViewModels:SecondViewModel}">
<Views:Second />
</DataTemplate>
</Application.Resources>
</Application>
MainWindow.xaml
<Window
x:Class="NavigationMVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NavigationMVVM"
xmlns:viewModels="clr-namespace:NavigationMVVM.ViewModels"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
Title="MainWindow"
Height="450"
Width="800">
<Window.DataContext>
<viewModels:MainViewModel />
</Window.DataContext>
<Grid>
<ContentControl
Content="{Binding ActualView}" />
</Grid>
</Window>
BaseViewModel.cs
using System.ComponentModel;
namespace NavigationMVVM.Common
{
public class BaseViewModel : INotifyPropertyChanged
{
private BaseViewModel _ActualView;
public BaseViewModel ActualView
{
get => _ActualView;
set
{
_ActualView = value;
RaisePropertyChanged(null);
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
#endregion
}
}
MainViewModel.cs
using NavigationMVVM.Common;
using NavigationMVVM.Models;
using System.Windows.Input;
namespace NavigationMVVM.ViewModels
{
public class MainViewModel : BaseViewModel
{
public DataManager SharedData = new DataManager();
public InitialViewModel InitialVM;
public FirstViewModel FirstVM;
public SecondViewModel SecondVM;
public LoginViewModel LoginVM;
public MainViewModel()
{
LoginVM = new LoginViewModel(SharedData);
InitialVM = new InitialViewModel(SharedData);
FirstVM = new FirstViewModel(SharedData);
SecondVM = new SecondViewModel(SharedData);
ActualView = InitialVM;
//ActualView = LoginVM;
}
public ICommand DisplayFirstView
{
get
{
return new RelayCommand(action => ActualView = FirstVM,
canExecute => true);
}
}
public ICommand DisplaySecondView
{
get
{
return new RelayCommand(action => ActualView = SecondVM,
canExecute => true);
}
}
public ICommand DisplayInitialView
{
get
{
return new RelayCommand(action => ActualView = InitialVM,
canExecute => true);
}
}
}
}
LoginViewModel.cs
using NavigationMVVM.Common;
using NavigationMVVM.Models;
using System.Diagnostics;
using System.Windows.Input;
namespace NavigationMVVM.ViewModels
{
public class LoginViewModel : BaseViewModel
{
private DataManager _DataManager;
public ICommand LoginCmd;
public RelayCommand DoLoginCmd { get; }
private string _Username;
public string Username
{
get => _Username;
set
{
_Username = value;
RaisePropertyChanged(null);
}
}
private string _Password;
public string Password
{
get => _Password;
set
{
_Password = value;
RaisePropertyChanged(null);
}
}
private string _MessageInfo;
public string MessageInfo
{
get => _MessageInfo;
set
{
_MessageInfo = value;
RaisePropertyChanged(null);
}
}
public LoginViewModel(DataManager sharedData)
{
_DataManager = sharedData;
DoLoginCmd = new RelayCommand(param => DoLogin(), canExec => (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password)));
}
public void DoLogin()
{
if (Username == "admin" && Password == "password")
{
_DataManager.User.Name = "Administrator";
_DataManager.User.Mail = "admin@company.com";
MessageInfo = "Login OK!... How to redirect??";
}
else
{
MessageInfo = "Username or Password incorrect!";
}
}
}
}
谢谢。
有多种方法可以完成您想要的。我将 post 在 MVVM 模式中工作时非常常见的两种方法
基于事件的方法:
public MainViewModel()
{
LoginVM = new LoginViewModel(SharedData);
LoginVM.PropertyChanged += LoginVM_PropertyChanged;
InitialVM = new InitialViewModel(SharedData);
FirstVM = new FirstViewModel(SharedData);
SecondVM = new SecondViewModel(SharedData);
//ActualView = InitialVM;
ActualView = LoginVM;
}
private void LoginVM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if(sender.GetType() == typeof(LoginViewModel) && e.PropertyName == "MessageInfo")
{
var loginVM = (LoginViewModel)sender;
if (loginVM.MessageInfo == "OK")
{
ActualView = InitialVM;
}
}
}
Cunstructor 注入:
private Action _loginAction;
public LoginViewModel(DataManager sharedData, Action loginAction )
{
_DataManager = sharedData;
DoLoginCmd = new RelayCommand(param => DoLogin(), canExec => (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password)));
_loginAction = loginAction;
}
public void DoLogin()
{
if (Username == "admin" && Password == "password")
{
_DataManager.User.Name = "Administrator";
_DataManager.User.Mail = "admin@company.com";
MessageInfo = "Login OK!... How to redirect??";
_loginAction.Invoke();
}
else
{
MessageInfo = "Username or Password incorrect!";
}
}
和
public MainViewModel()
{
LoginVM = new LoginViewModel(SharedData, () => ActualView = InitialVM);
InitialVM = new InitialViewModel(SharedData);
FirstVM = new FirstViewModel(SharedData);
SecondVM = new SecondViewModel(SharedData);
//ActualView = InitialVM;
ActualView = LoginVM;
}
旁注:在 BaseViewModel 上放置 属性“ActualView”是一个相当奇怪的选择