You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF MVVM模式下登录后导航至MainWindow视图不显示问题

WPF MVVM登录后导航到MainWindow视图不显示问题

我是WPF与MVVM模式的新手,尝试创建LoginWindow和包含HomeView等UserControl的MainWindow。以下是我的实现代码,目前遇到登录成功后导航到MainViewModel,但MainWindow视图未切换显示的问题。

1. App.xaml.cs 服务初始化代码

public App()
{
    IServiceCollection services = new ServiceCollection();

    services.AddSingleton(Provider => new LoginPage
    {
        DataContext = Provider.GetRequiredService<LoginViewModel>()
    });
    services.AddSingleton<MainViewModel>();
    services.AddSingleton<HomeViewModel>();
    services.AddSingleton<LoginViewModel>();
    services.AddSingleton<INavigationService, NavigationServices>();
    services.AddSingleton<Func<Type, ViewModel>>(serviceProvider => viewModelType => (ViewModel)serviceProvider.GetRequiredService(viewModelType));
    
    serviceProvider = services.BuildServiceProvider();
}

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    
    if(serviceProvider != null)
    {
        var loginPage = serviceProvider.GetRequiredService<LoginPage>();
        loginPage.Show();
    }
    else
    {
        Debug.WriteLine("Service Provider is null");
    }
    
}

2. App.xaml 资源配置

<Application x:Class="NewHRD.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:NewHRD"
             xmlns:viewModel="clr-namespace:NewHRD.MVVM.ViewModels"
             xmlns:view="clr-namespace:NewHRD.MVVM.Views">
    <Application.Resources>
        <DataTemplate DataType="{x:Type TypeName=viewModel:MainViewModel}">
            <view:MainWindow/>
        </DataTemplate>

        <DataTemplate DataType="{x:Type TypeName=viewModel:HomeViewModel}">
            <view:HomeView/>
        </DataTemplate>
        
    </Application.Resources>

</Application>

3. LoginViewModel 登录命令代码

private async void ExecuteLoginCommand(object arg)
{
    string valid = await APIUser.AuthenticateUser("user/Login", Username, Password);
    if (valid != null)
    {
        JObject jsonObject = JObject.Parse(valid);

        // Extract the "data" part from the JObject
        JToken dataToken = jsonObject["data"];
        Dictionary<string, object> data = dataToken.ToObject<Dictionary<string, object>>();

        DynamicModel dynamicModel = new DynamicModel(data);
        var principal = new GenericPrincipal(
            new GenericIdentity(Username), new string[] { data["access_rights_name"].ToString() });
        Thread.CurrentPrincipal = principal;
        AppDomain.CurrentDomain.SetThreadPrincipal(principal);
        if (MessageBox.Show($"Masuk sebagai {Username} ?", "Logged In", MessageBoxButton.OKCancel,
            MessageBoxImage.Information) == MessageBoxResult.OK)
        {
            IsHomeButtonVisible = "Visible";
            Window curWind = System.Windows.Application.Current.MainWindow;
            Navigation.NavigateTo<MainViewModel>();
        }
    }
    else
    {
        Debug.WriteLine("Hmmm...");
    }
}

4. 导航服务实现代码

public interface INavigationService
{
    ViewModel CurrentView { get; }

    void NavigateTo<T>() where T : ViewModel;
}
internal class NavigationServices : ObservableObject, INavigationService
{
    private readonly Func<Type, ViewModel> _viewModelFactory;
    private ViewModel _currentView;

    public ViewModel CurrentView
    {
        get => _currentView;
        set
        {
            _currentView = value;
            OnPropertyChanged();
        }
    }
    public NavigationServices(Func<Type, ViewModel> viewModelFactory)
    {
        _viewModelFactory = viewModelFactory;
    }
    public void NavigateTo<TViewModel>() where TViewModel : ViewModel
    {
        ViewModel viewModel = _viewModelFactory.Invoke(typeof(TViewModel));
        CurrentView = viewModel;
    }

}

问题现象

调试时确认已进入MainViewModel构造逻辑,但MainWindow视图并未显示,登录窗口依然存在,视图未完成切换。


问题分析与解决方案

核心问题

  1. DataTemplate 误用:你在App.xaml中给MainViewModel绑定了MainWindow的DataTemplate,但MainWindow是顶级窗口(Window类型),不是可嵌入的UI元素(如UserControl)。WPF的DataTemplate用于将ViewModel渲染为可视化元素,但Window不能作为DataTemplate的根元素被动态加载,这种绑定方式无效。

  2. 导航逻辑未处理窗口切换:当前的NavigationService只是更新了CurrentView的ViewModel,但没有处理窗口的关闭与新窗口的打开逻辑——你需要在登录成功后关闭LoginPage,然后实例化并显示MainWindow。

修复步骤

步骤1:修正App.xaml中的DataTemplate配置

将MainViewModel对应的DataTemplate改为针对MainWindow内部的内容区域(比如MainWindow里有一个ContentControl用于显示HomeView等),而不是绑定整个Window。如果MainWindow是独立的顶级窗口,直接移除这个DataTemplate:

<Application.Resources>
    <!-- 只保留UserControl类型视图的DataTemplate -->
    <DataTemplate DataType="{x:Type viewModel:HomeViewModel}">
        <view:HomeView/>
    </DataTemplate>
</Application.Resources>

步骤2:调整登录后的窗口切换逻辑

因为MainWindow是独立窗口,不需要通过DataTemplate导航,直接在登录成功后关闭当前LoginPage并打开MainWindow:

修改ExecuteLoginCommand中的逻辑:

if (MessageBox.Show($"Masuk sebagai {Username} ?", "Logged In", MessageBoxButton.OKCancel,
    MessageBoxImage.Information) == MessageBoxResult.OK)
{
    IsHomeButtonVisible = "Visible";
    // 关闭当前登录窗口
    var loginWindow = Application.Current.Windows.OfType<LoginPage>().FirstOrDefault();
    loginWindow?.Close();
    
    // 从服务容器获取MainWindow并显示
    var mainWindow = App.Current.serviceProvider.GetRequiredService<MainWindow>();
    mainWindow.Show();
}

步骤3:在服务容器中注册MainWindow

在App.xaml.cs的服务注册代码中添加MainWindow的注册:

services.AddSingleton(Provider => new MainWindow
{
    DataContext = Provider.GetRequiredService<MainViewModel>()
});

步骤4:MainWindow内部视图导航配置(可选)

如果MainWindow内部需要切换HomeView等UserControl,确保MainWindow的XAML中有绑定到MainViewModel中视图属性的ContentControl:

<!-- MainWindow.xaml -->
<Grid>
    <ContentControl Content="{Binding CurrentView}" />
</Grid>

然后在MainViewModel中注入INavigationService,维护内部视图切换逻辑:

public class MainViewModel : ViewModel
{
    private readonly INavigationService _navigationService;

    public ViewModel CurrentView => _navigationService.CurrentView;

    public MainViewModel(INavigationService navigationService)
    {
        _navigationService = navigationService;
        // 初始化时导航到HomeView
        _navigationService.NavigateTo<HomeViewModel>();
    }
}

这样就能同时实现登录窗口到主窗口的切换,以及主窗口内部的视图导航。


内容的提问来源于stack exchange,提问作者Qu Da

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 19:54:52