Skip to content

页面结构 ​

星云桌面端的界面是 WinUI 3 写的。这一页讲页面怎么组织、怎么导航、怎么刷新。

导航是插件驱动的 ​

侧栏不是写死的列表。启动器启动时读内核的贡献点注册表,把 NavItem 类型的贡献渲染成导航项。

csharp
// MainWindow.BuildNavFromContributions()
foreach (var c in Kernel.Contributions.Of(ContributionKind.NavItem))
{
    if (c.Target == "separator") { /* 插分隔线 */ }
    else if (c.Target == "footer") { /* 进底部区 */ }
    else { /* 进主区 */ }
}

这条设计是插件系统能长出界面的前提——插件往注册表里登记一个导航项,外壳下次重建时它就出现了。插件页也不占侧栏的固定位置(数量有限,排在插件组里)。

细节见窗口与导航。

页面清单 ​

一级页面 ​

页面干什么
首页版本列表 + 账户/启动卡。点启动后盖住两列内容
版本已安装版本管理,搜索、分类过滤、右键菜单
下载安装原版与社区资源
存档跨版本列出所有世界,备份、删除、跨版本启动
账户Starcloud ID 卡片 + 账户列表
实验室投影工坊、彩色文字
好友两栏:会话列表 + 聊天
插件安装、启停、卸载
设置外观、路径、内存、Java、并发、下载源、跨设备互联、语言
运行状态这一局在干什么:CPU/内存/GPU 曲线、启动配置、日志尾
联机建房、进房、状态

联机页不进侧栏,它是好友页里的一个分区。

二级页面 ​

二级页不占侧栏选中项,用 drill-in 转场推进。

页面从哪进
版本详情版本列表点条目
添加账户账户页右上角
账户详情账户列表点条目
插件面板页插件页点插件的「面板」
投影管理实验室里

三种导航方式 ​

csharp
// 二级页:drill-in 转场,不改侧栏选中项
ContentFrame.Navigate(typeof(VersionDetailPage), versionId,
    MotionService.TransitionFor(enabled, drillIn: true));

// 侧栏页:由贡献点路由
var pageType = ResolvePageType(tag);
ContentFrame.Navigate(pageType);

// 返回上一级
ContentFrame.Navigate(typeof(HomePage), null,
    MotionService.BackTransition(enabled));

TransitionFor 在动效关闭时返回 SuppressNavigationTransitionInfo——不是"不转场"。不转场在 WinUI 3 里会闪。

启动覆盖层 ​

点启动后,首页两列内容被一层盖住,显示启动进度。

进度是「氛围进度」——每 250ms 爬 0.5%,到顶就停,不承诺精确。这是刻意的:真实的准备步骤(Java 探测、预检补全)没有可量化的百分比,给一个会动的数字比给一个卡在 0% 的进度条体验好。

csharp
// HomePage 的三只定时器
_logTimer.Interval    = TimeSpan.FromMilliseconds(100);  // 实时日志尾
_stageTimer.Interval = TimeSpan.FromMilliseconds(250);  // 氛围进度爬升
_windowTimer.Interval= TimeSpan.FromMilliseconds(500);  // 轮询游戏窗口是否出现

运行状态页的三层刷新 ​

这个页面的刷新刻意分三层,不对齐频率:

采样回调(1s,后台线程)→ 只更新数字、曲线、日志尾
                          (选中实例与实例集合都没变就不重建列表)
实例变化(起 / 止 / 下拉换选中)→ 整页重建
1s UI 定时器            →  只刷「已运行 00:42:17」

如果全按 1s 整页重建,列表会一直闪;如果只靠采样回调,已运行时长在采样暂停时就不走了。

配套的生命周期处理:

csharp
// RunningStatusPage
NavigationCacheMode = NavigationCacheMode.Disabled;

每次进入都是新实例,Loaded 订阅 / Unloaded 退订,避免事件订阅泄漏。

对话框 ​

所有弹窗走 ThemedDialog 基类。

为什么需要这个基类:WinUI 3 的弹层(PopupRoot)不继承 Window.Content 上的 RequestedTheme,浅色主题下弹窗会跟随系统变成深色。所以显示前要把 RequestedTheme 显式钉到 xamlRoot 根元素的 ActualTheme。

同一时刻只允许一个 ContentDialog。所以下载进度、修复进度都画在弹窗内部,不嵌套二级对话框。涉及多阶段的弹窗(崩溃分析、自更新)用阶段机实现:取消当前阶段、显示新内容、再取消。

csharp
// 阶段机:args.Cancel + GetDeferral
private void OnClosing(ContentDialog sender, ContentDialogClosingEventArgs args)
{
    if (_stage < _stages.Count)
    {
        args.Cancel = true;                    // 拦住关闭
        var deferral = args.GetDeferral();     // 异步换内容
        _stage++;
        ShowStage(_stages[_stage]);
        deferral.Complete();
    }
}

相关链接:窗口与导航 · 外观与动效系统 · 自绘控件与交互行为 · 运行态与防双开

基于 MIT 许可证(有修改)开源