如何使用具有多个页面和导航的 WPF 处理依赖注入?

How to handle dependency injection with WPF with multiple pages and navigation?

我一直在尝试在 WPF 中做以下事情:

而且...

我有:

所以,在堆栈论坛中寻找解决方案后,我最终采用了这种组合方法。

App.xaml 开始,所有服务和视图模型都已初始化,主要 window 通过注入接收其视图模型:

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 通过注入接收所有其他视图模型并将它们存储在 属性。

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();
    }
}

所有页面视图模型都继承自此接口,因此可以按名称从集合中检索它们,然后在需要时添加为 SelectedPage。

public interface IPageViewModel : INotifyPropertyChanged
{
    public string PageTitle { get; set; }
}

window 有一个内容控件,其中 属性 内容绑定到 SelectedPage,因此它已更新。

<Window>
   <ContentControl Content="{Binding SelectedPage}" />
</Window>

并且它知道通过这些数据模板为每个视图模型使用哪个视图。

<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];
    }
}

问题

我也许可以在所有子模型中注入 mainviewmodel,但这看起来不太好,事实上从一开始很多事情都是一团糟。

例如,我必须:

我可能做错了,我需要帮助。

有很多可能的解决方案。简单的就是介绍一个事件

我还建议将 select 视图模型的责任移动并限制到 MainViewModel。其他页面模型不应该知道谁 select 是谁的流程。否则这会增加一个太紧的耦合,这在这一点上是可以避免的。

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; }

  ...
}