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

如何使用ReactiveUI实现类似Visual Studio的启动窗口?

你的ViewModel层级设计是合理的,不需要做大幅度调整,以下是可直接落地的实现方案:

1. 路由与数据留存解决方案

你担心的跳转数据丢失、按钮不固定、手动导航失效的问题都可以通过嵌套路由的方式解决:

  • 最外层StartWindowViewModel作为根路由宿主,持有全局RoutingState,负责切换根级视图:StartViewModel(启动页)和ProjectCreationViewModel(项目创建向导),根视图切换和按钮逻辑完全解耦,不会出现手动导航失效的问题
  • ProjectCreationViewModel作为向导内部的子路由宿主,自己持有一个独立的RoutingState,负责切换内部的Page1和Page2;同时它直接持有ProjectCreationPage1ViewModel和ProjectCreationPage2ViewModel的单例,跳转时复用同一实例,所有输入数据都会完整保留
  • 所有页面的底部按钮逻辑都放在对应页面的ViewModel中实现,不需要和路由绑定做全局固定按钮,完全适配你不同页面按钮不同的需求

2. 核心代码实现示例

根路由配置(StartWindowViewModel)

public class StartWindowViewModel : ReactiveObject, IScreen
{
    // 全局根路由状态
    public RoutingState Router { get; } = new RoutingState();

    public StartWindowViewModel()
    {
        // 初始化默认显示启动页
        Router.Navigate.Execute(new StartViewModel(this));
    }
}

启动页跳转逻辑(StartViewModel)

public class StartViewModel : ReactiveObject, IRoutableViewModel
{
    public IScreen HostScreen { get; }
    public string UrlPathSegment => "StartPage";

    // 创建新项目命令,绑定到「创建新项目...」按钮
    public ReactiveCommand<Unit, IRoutableViewModel> GoToCreateProject { get; }

    public StartViewModel(IScreen hostScreen)
    {
        HostScreen = hostScreen;
        GoToCreateProject = ReactiveCommand.CreateFromObservable(
            () => HostScreen.Router.Navigate.Execute(new ProjectCreationViewModel(HostScreen))
        );
    }
}

项目向导父ViewModel配置

public class ProjectCreationViewModel : ReactiveObject, IScreen, IRoutableViewModel
{
    public IScreen HostScreen { get; }
    public string UrlPathSegment => "ProjectCreationWizard";
    // 向导内部子路由状态
    public RoutingState Router { get; } = new RoutingState();
    // 常驻两个页面实例,保证数据不丢失
    public ProjectCreationPage1ViewModel Page1 { get; }
    public ProjectCreationPage2ViewModel Page2 { get; }

    public ProjectCreationViewModel(IScreen rootHost)
    {
        HostScreen = rootHost;
        Page1 = new ProjectCreationPage1ViewModel(this);
        Page2 = new ProjectCreationPage2ViewModel(this);
        // 初始化显示第一页
        Router.Navigate.Execute(Page1);
    }
}

页面跳转逻辑实现

  • Page1的Cancel命令直接调用根路由的NavigateBack返回启动页
  • Page1的Next命令调用向导子路由的Navigate.Execute(Page2)跳转到第二页
  • Page2的Back命令调用向导子路由的NavigateBack返回第一页,因为Page1实例常驻,所有输入数据都会保留
  • Page2的Finish命令收集Page1和Page2的配置组装成ProjectModel,可以通过消息总线、回调或者根路由的参数传递给启动页,之后调用根路由的NavigateBack返回启动页

3. View层适配

  • 最外层StartWindowView中放置一个RoutedViewHost,绑定到StartWindowViewModel.Router,用于全局根视图切换
  • ProjectCreationView内部再放置一个RoutedViewHost,绑定到ProjectCreationViewModel.Router,用于向导内部页面切换
  • 每个页面的底部按钮直接放在对应Page的View中,不需要做全局固定按钮,完全实现类似VS的整页切换效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 01:36:04