我一直在尝试在 WPF 中执行以下操作:
- 带有登录页面和主页的窗口。
- 成功验证用户身份后,窗口应显示主页。
- 它应该通过使用 native WPF 依赖项注入(inject)框架来工作。
但也...
- 可能有页面 3、4、5,并且每个页面都应该能够相互调用。
- 也许每个页面中都可以包含可以互相调用的页面。
- 因此,如果可能的话,该解决方案应该能够使用嵌套页面和导航。
我有什么:
因此,在堆栈论坛中寻找解决方案后,我最终采用了这种组合方法。
从App.xaml开始,所有服务和 View 模型都被初始化,主窗口通过注入(inject)接收其 View 模型:
private void ConfigureServices(ServiceCollection services)
{
services.AddSingleton<MainWindow>();
//ViewModels
services.AddSingleton<MainViewModel>();
services.AddSingleton<AuthViewModel>();
services.AddSingleton<HomeViewModel>();
}
private void OnStartup(object sender, StartupEventArgs e)
{
var mainWindow = serviceProvider.GetService<MainWindow>();
mainWindow.DataContext = serviceProvider.GetService<MainViewModel>();
mainWindow.Show();
}
然后,mainViewModel 通过注入(inject)接收所有其他 View 模型并将它们存储在属性中。
public class MainViewModel
{
public IPageViewModel SelectedPage {get; set; } //PropertyChanged() removed for brevity.
public ObservableCollection<IPageViewModel> Pages {get; set;}
public MainViewModel(AuthViewModel authViewModel, HomeViewModel homeViewModel)
{
this.Pages = new ObservableCollection<IPageViewModel>() { authViewModel, homeViewModel};
this.SelectedPage = this.Pages.First();
}
}
所有页面 View 模型都继承自此接口(interface),因此可以按名称从集合中检索它们,然后在需要时将其添加为 SelectedPage。
public interface IPageViewModel : INotifyPropertyChanged
{
public string PageTitle { get; set; }
}
窗口有一个内容控件,其属性内容绑定(bind)到 SelectedPage,以便更新。
<Window>
<ContentControl Content="{Binding SelectedPage}" />
</Window>
并且它通过这些数据模板知道每个 View 模型要使用哪个 View 。
<Application.Resources>
<DataTemplate DataType="{x:Type vm:AuthViewModel}">
<views:AuthView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:HomeViewModel}">
<views:HomeView />
</DataTemplate>
</Application.Resources>
但是...我注意到这不起作用,我只能从 mainViewModel 中调用 SelectedPage 上的更改。
public class AuthViewModel : BaseViewModel
{
public AuthViewModel() { }
public void AttemptLogin() {
// how
SelectedPage = Pages[1];
}
}
问题
我也许可以在所有子模型中注入(inject) mainviewmodel,但这看起来不太好,事实上从一开始很多事情就有点困惑。
例如,我必须:
- 为我创建的每个 View 模型添加一个服务 View 模型到 app.xaml。
- 将它们中的每一个添加为主窗口 View 模型的参数,这看起来很难看。
我可能做错了,我需要帮助。
最佳答案
有很多可能的解决方案。一个简单的方法就是引入一个事件。
我还建议将选择 View 模型的责任转移并限制到 MainViewModel
。其他页面模型不应该知道像谁选择谁这样的流程。否则,这会增加过于紧密的耦合,这在此时是可以避免的。
public class MainViewModel
{
public IPageViewModel SelectedPage { get; set; }
private Dictionary<string, IPageViewModel> Pages { get; }
public MainViewModel(AuthViewModel authViewModel, HomeViewModel homeViewModel)
{
authViewModel.AuthenticationPassed += OnAuthenticationSuccessfull;
this.Pages = new Dictionary<string, IPageViewModel>()
{
{ nameof(AuthViewModel), authViewModel },
{ nameof(HomeViewModel), homeViewModel }
};
this.SelectedPage = this.Pages[nameof(AuthViewModel)];
}
public OnAuthenticationSuccessfull(object sender, EventArgs e)
{
(sender as AuthViewModel).AuthenticationPassed -= OnAuthenticationSuccessfull;
this.SelectedPage = this.Pages[nameof(HomeViewModel)];
}
}
class AuthViewModel
{
public event EventHandler AuthenticationPassed { get; }
...
}
关于c# - 如何使用具有多个页面和导航的 WPF 处理依赖注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66578575/