
音视频桌面应用【免费下载链接】Bili.Uwp适用于新系统UI的哔哩项目地址https://gitcode.com/GitHub_Trending/bi/Bili.Uwp点击查看免费下载导读视图模型ViewModel是 MVVM 架构中连接数据与界面的核心枢纽。本文以 Bili.Uwp 项目中src/ViewModels/ViewModels.Uwp视图模型层的项目文档为骨架深入剖析其在 MVVM 设计中的定位、页面级与功能级视图模型的划分思路以及应用视图模型AppViewModel、媒体播放器视图模型MediaPlayerViewModel、导航视图模型NavigationViewModel三大核心组件的职责边界与源码实现。读完本文你将理解一个大型 UWP 客户端应用如何组织视图模型体系以及播放器、字幕、弹幕、导航、账户等功能模块如何在 ViewModel 层完成协作。一、视图模型在 MVVM 设计中的定位项目 README 开篇即点明了视图模型的地位视图模型在 MVVM 设计中所占的比重不言而喻并给出了本项目遵循的核心设计思路——功能与视图分离。这一思路落地为两条明确规则每个页面都有自己对应的视图模型页面负责布局与交互呈现页面视图模型负责承载数据、状态与命令页面通过数据绑定消费视图模型暴露的属性与命令相对独立的功能拥有独立的视图模型例如播放、账户这类横跨多个页面、生命周期较长的功能不挂靠在某个页面下而是独立成模块便于复用与解耦。从目录结构上可以直观看到这两类视图模型的并存src/ViewModels/ViewModels.Uwp/下的Home、Live、Pgc、Search、Article、Video、Community、Account等目录对应业务域下的页面视图模型而Common目录如SubtitleModuleViewModel、DanmakuModuleViewModel、DownloadModuleViewModel、InteractionModuleViewModel以及Core目录三大核心视图模型则是功能模块视图模型。视图模型层的项目引用结构从 ViewModels.Uwp.csproj 的ProjectReference可以看出视图模型层在整个架构中的位置——它位于业务能力之上、界面之下直接依赖被引用项目提供能力Adapter.Interfaces数据适配层接口Bili 接口的适配封装Lib.Interfaces业务提供者接口播放、直播、PGC、搜索等Models.App/Models.Data/Models.Enums应用常量、数据模型、枚举类型Toolkit.Interfaces工具服务接口设置、资源、字体、数字等ViewModels.Interfaces视图模型接口定义同层接口见src/ViewModels/ViewModels.InterfacesDI.Container依赖注入容器Autofac 封装见 Locator.cs视图模型层通过构造器注入I*Provider与I*Toolkit服务自己不直接触碰网络细节这一分层保证了视图模型只管状态与命令编排的单一职责。二、三大核心视图模型README 明确指出本项目的视图模型核心有三个它们处于Core目录下src/ViewModels/ViewModels.Uwp/Core。2.1 应用视图模型AppViewModel职责处理应用整体的显示状态并作为中转站传递部分调用例如跨页面触发更新检查、动态注册检查等。从 AppViewModel.cs 与 AppViewModel.Properties.cs 的源码可以看到它的实际工作内容平台与形态判断构造时通过AnalyticsInfo.VersionInfo.DeviceFamily判断是否运行在 Xbox 上IsXbox并默认展开导航面板IsNavigatePaneOpen true网络状态监测挂接NetworkHelper.Instance的NetworkChanged事件维护IsNetworkAvaliable属性语言与本地化读取系统语言首选项并写入LastAppLanguage设置同时判断是否为繁体中文环境IsTraditionalChinese这为后续繁简字幕转换、资源切换提供依据版本更新与动态通知注册暴露CheckUpdateCommand、CheckNewDynamicRegistrationCommand两个异步命令并统一挂接异常处理AttachExceptionHandlerToAsyncCommand(LogException, ...)响应式边距计算InitializePadding()根据窗口宽度与MediumWindowThresholdWidthKey阈值从资源DefaultPageHorizontalPadding/NarrowPageHorizontalPadding/XboxPageHorizontalPadding中取出对应边距实现窄屏、宽屏、Xbox 三种形态的布局适配。值得留意的是AppViewModel 的构造器注入了ICallerViewModel与INavigationViewModel这正是 README 所说中转站角色的体现——应用级命令如更新检查完成后可以通过 Caller 触发全局提示Tip通过 Navigation 发起页面跳转。2.2 媒体播放器视图模型MediaPlayerViewModel职责负责视频的播放下辖字幕视图模型SubtitleModuleViewModel与弹幕视图模型DanmakuModuleViewModel基本涵盖视频操作的各个方面。从 MediaPlayerViewModel.cs 与 MediaPlayerViewModel.Properties.cs 可以看出其核心设计统一承载三类内容通过SetVideoData(VideoPlayerView)、SetPgcData(PgcPlayerView, EpisodeInformation)、SetLiveData(LivePlayerView)三个入口分别接收普通视频、PGC番剧/影视与直播数据内部以VideoType枚举区分播放类型并在ReloadCommand驱动的LoadAsync()中分流到LoadVideoAsync/LoadEpisodeAsync/LoadLiveAsync播放器引擎可插拔InitializePlayer()根据设置项PlayerType默认Native从 DI 容器Locator.Instance.GetService...()解析INativePlayerViewModel或IFFmpegPlayerViewModel直播流固定使用 FFmpeg 播放器。播放器切换、格式切换、进度上报等事件统一在 MediaPlayerViewModel 中汇聚音视频源选择与清晰度管理SelectVideoFormatAsync见 MediaPlayerViewModel.Video.cs按用户设置的清晰度筛选VideoSegments并依据偏好解码器Codec匹配分段音频分段直接选择最大码率若当前清晰度源不可用则回退到最大质量分段同时把DefaultVideoFormat写回本地设置实现清晰度记忆P2P CDN 剔除CheckVideoP2PUrls()MediaPlayerViewModel.Video.cs在用户开启DisableP2PCdn设置时将 BaseUrl 非bilivideo.com的分段替换为官方的备用地址规避 P2P 加速源进度记忆与续播CheckVideoHistory()读取播放记录若上次处于播放状态则弹出上次看到 xx的提示IsShowProgressTip/ProgressTip系统集成通过SystemMediaTransportControls接入系统媒体控制SMTC支持锁屏/系统媒体面板操作ActiveDisplay()/ReleaseDisplay()使用DisplayRequest保持/释放屏幕常亮模块委托SubtitleViewModel、DanmakuViewModel、InteractionViewModel作为公开属性暴露给界面播放视频时通过SubtitleViewModel.SetData(...)与DanmakuViewModel.SetData(...)把视频标识mainId、partId下发给字幕与弹幕模块MediaPlayerViewModel.Video.cs。此外MediaPlayerViewModel.Commands.cs、MediaPlayerViewModel.Controls.cs、MediaPlayerViewModel.Episode.cs、MediaPlayerViewModel.Live.cs、MediaPlayerViewModel.Method.cs等 partial 文件按命令、控件、分集、直播、方法维度拆分了播放器的庞大职责是项目功能与视图分离 partial 组织风格的典型体现。字幕模块视图模型SubtitleModuleViewModelSubtitleModuleViewModel.cs 是播放器下辖的独立功能模块SetData(mainId, partId)接收视频标识后触发ReloadCommand加载流程分两步先通过IPlayerProvider.GetSubtitleIndexAsync(mainId, partId)获取字幕元数据Metas再通过GetSubtitleDetailAsync(meta.Url)拉取具体字幕内容Seek(sec)根据当前播放时间在字幕列表中做区间匹配找到StartPosition sec EndPosition的字幕并更新CurrentSubtitle繁简转换ConvertType设置支持None/ToTraditionalChinese/ToSimplifiedChinese借助ToolGood.Words.WordsHelper实时转换字幕文本转换偏好通过SubtitleConvertType设置持久化见OnConvertTypeChangedCanShowSubtitle是否显示字幕同样持久化到本地设置。弹幕模块视图模型DanmakuModuleViewModelDanmakuModuleViewModel.cs 与字幕模块对称SetData(mainId, partId, videoType)支持普通视频与直播两种弹幕场景分段拉取LoadSegmentDanmakuAsync(index)调用IPlayerProvider.GetSegmentDanmakuAsync按段获取弹幕并通过DanmakuListAdded事件追加到渲染层避免一次性加载全部弹幕发送弹幕SendDanmakuAsync根据VideoType分流到SendVideoDanmakuAsync走IPlayerProvider.SendDanmakuAsync携带当前播放秒数、颜色、字号与位置或SendLiveDanmakuAsync走ILiveProvider.SendDanmakuAsync失败时通过ICallerViewModel.ShowTip弹出错误提示弹幕字体集合、位置选项、颜色选项以ObservableCollection暴露供设置面板绑定。2.3 导航视图模型NavigationViewModel职责处理页面导航及层级转换。README 特别注明目前尚不完善这是作者对其当前成熟度的如实评估读者可结合源码自行判断其已覆盖的能力。从 NavigationViewModel.cs 的实现看其核心机制包括三级导航类型Navigate(PageIds pageId, object parameter null)依据页面枚举的 HashCode 数值区间自动判定导航类型——小于 100 为主视图NavigationType.Main、小于 1000 为次级视图NavigationType.Secondary、其余进入播放视图NavigationType.Player三层视图互斥IsMainViewShown、IsSecondaryViewShown、IsPlayViewShown三个布尔属性互斥切换见三个partial void On*ShownChanged保证任一时刻只显示一种层级回退栈Back Stack内部维护ListAppBackEventArgs通过AddBackStack(BackBehavior, Actionobject, parameter)记录每个导航动作及其回退行为Back命令弹出栈顶并执行其回退动作TryLayerBack根据栈顶的BackBehaviorMainView/SecondaryView/OpenPlayer分别恢复主视图、次级视图或播放快照PlaySnapshot播放器与弹层清理切换视图时CloseAllPopup()关闭ShowHolder类型的弹层、RemoveAllPlayer()销毁OpenPlayer回退项并触发ExitPlayer事件避免播放器在后台持续占用资源回退可用性CheckBackStatus()依据栈深度Count 1与栈顶类型维护CanBack与IsBackButtonEnabled跨页触发Navigating事件携带AppNavigationEventArgs导航类型、目标页、参数供 RootPage 等界面层响应实际切换。从 NavigationViewModel.Properties.cs 可见其构造依赖IRecordViewModel用于在返回主/次级视图时清理最近播放记录DeleteLastPlayItemCommand。三、页面视图模型与功能模块视图模型的划分除三大核心外README 指出其它的视图模型则按照各自的功能进行划分。按业务域盘点如下均位于 src/ViewModels/ViewModels.UwpAccount账户域AccountViewModel登录态、会员信息、UserSpaceViewModel用户空间、FavoritePageViewModel收藏页、HistoryPageViewModel历史记录、MyFollowsPageViewModel、ViewLaterPageViewModel稍后再看、XboxAccountPageViewModel、UserItemViewModelHome首页域RecommendPageViewModel推荐、PopularPageViewModel热门、RankPageViewModel排行榜、SettingsPageViewModel设置、ToolboxPageViewModel、HelpPageViewModelVideo视频域VideoPlayerPageViewModel播放页含 Initialize/Methods/Request/Reset/Exception 等 partial 分件、VideoPartitionPageViewModel、VideoPartitionDetailPageViewModel、VideoItemViewModel及收藏夹相关VideoFavoriteModuleViewModel等PgcPGC 域BangumiPageViewModel、MoviePageViewModel、DocumentaryPageViewModel、DomesticPageViewModel、TvPageViewModel、TimelinePageViewModel时间线、PgcPlayerPageViewModelPGC 播放页、EpisodeItemViewModel、SeasonItemViewModel等Live直播域LiveFeedPageViewModel、LivePartitionPageViewModel、LivePartitionDetailPageViewModel、LivePlayerPageViewModel、LiveItemViewModelSearch搜索域SearchPageViewModel含 Filters/Request 分件、SearchBoxViewModel、SearchFilterViewModel、SearchModuleItemViewModelArticle专栏域ArticlePartitionPageViewModel、ArticleItemViewModel、ArticleFavoriteModuleViewModelCommunity社区域DynamicPageViewModel、MessagePageViewModel、CommentPageViewModel、CommentDetailModuleViewModel、CommentMainModuleViewModel、CommentItemViewModel、DynamicItemViewModel、FansPageViewModel、FollowsPageViewModel等Toolbox工具箱AvBvConverterViewModel、CoverDownloaderViewModel、ToolboxItemViewModel。页面视图模型普遍通过Base目录下的基类复用公共能力InformationFlowViewModelBase信息流页面推荐、分区、PGC 列表等的通用基类管理分页加载与增量请求DynamicModuleViewModelBase/PgcPageViewModelBase/AnimePageViewModelBase/RelationPageViewModelBase/PgcFavoriteModuleViewModelBase分别对应动态模块、PGC 页面、关系页关注/粉丝、PGC 收藏模块的共性逻辑SelectableViewModelBase{T}可选中项视图模型的泛型基类PlayerPageViewModelBase播放页视图模型的基类衔接MediaPlayerViewModel与页面级状态详情、相关视频、评论等。页面视图模型与播放器核心的协作示例以VideoPlayerPageViewModelsrc/ViewModels/ViewModels.Uwp/Video/VideoPlayerPageViewModel为例播放页自身的视图模型负责视频信息、分P列表、相关推荐、播放页评论等页面级数据而真正的播放控制清晰度、倍速、音量、字幕、弹幕、进度由Core/MediaPlayerViewModel承担。这种页面 VM 管内容、功能 VM 管播放的边界划分正是 README 所述相对独立的功能拥有独立视图模型的直接体现也让播放器可以在普通视频页、PGC 页、直播页之间复用。四、视图模型基类与公共设施ViewModelBase所有视图模型包括三大核心最终都继承自ViewModelBaseBase/ViewModelBase.cs该基类继承CommunityToolkit.Mvvm.ComponentModel.ObservableObject借助 CommunityToolkit MVVM 的源生成器[ObservableProperty]、[RelayCommand]简化属性通知与命令定义。基类提供的公共能力方法用途GetErrorMessage(Exception)从异常中提取用户可读的错误消息对ServiceException走其GetMessage()定制文案LogException(Exception)统一记录异常输出调试信息 通过Locator.Instance.GetLogger()NLog写日志FakeLoadingAsync()退避策略延迟约 250msAppConstants.FakeLoadingMilliseconds让界面先渲染加载中状态再渲染已有数据规避导航动画与列表渲染的资源竞争导致的 UI 卡顿注释中说明该值是估算值RunDelayTask(Task)并行执行任务并附带最小运行时长避免闪屏式刷新TryClearT(ObservableCollectionT)仅当集合非空时清空减少不必要的集合变更通知AttachExceptionHandlerToAsyncCommand(...)为IAsyncRelayCommand批量挂接异常处理监听ExecutionTask上的AggregateExceptionAttachIsRunningToAsyncCommand(...)批量将异步命令的IsRunning状态回写到 ViewModel 属性如IsReloading、IsDanmakuLoading这些设施在三大核心中广泛使用例如MediaPlayerViewModel构造时对ReloadCommand同时调用AttachIsRunningToAsyncCommand(p IsReloading p, ...)与AttachExceptionHandlerToAsyncCommand(DisplayException, ...)实现加载状态可绑定、异常统一展示。五、视图模型层与底层服务的协作依赖注入视图模型层不自行创建服务而是通过项目内封装的依赖注入容器获取依赖。src/Lib/DI.Container基于 Autofac 提供了LocatorLocator.cs支持RegisterSingletonTInterface, TImplementation()、RegisterTransientTInterface, TImplementation()与RegisterConstant(object)注册方式视图模型大多通过构造器注入获得I*Provider播放、直播、搜索、社区等与I*Toolkit设置、资源、字体、数字、应用工具。以MediaPlayerViewModel的构造器为例MediaPlayerViewModel.cs它同时注入了播放提供者、直播提供者、资源/设置/数字/应用工具、账户视图模型、导航视图模型、字幕/弹幕/互动模块视图模型、调用者视图模型与应用视图模型——一次注入即把播放所需的全部上下文编排齐备。而播放器引擎INativePlayerViewModel/IFFmpegPlayerViewModel则是在InitializePlayer()时通过Locator.Instance.GetService...()按需解析配合设置项PlayerType实现运行时可切换。Common下的DownloadModuleViewModel下载、InteractionModuleViewModel互动视频选择也沿用同样的模式以独立模块视图模型的形式被播放器或页面引用职责单一、可独立测试。六、依赖与构建环境视图模型项目 ViewModels.Uwp.csproj 的关键依赖PackageReference包括Microsoft.NETCore.UniversalWindowsPlatform6.2.14UWP 基础框架CommunityToolkit MVVMObservableObject/AsyncRelayCommand等的来源经由Microsoft.Toolkit.Uwp7.1.3 一并引入FFmpegInteropX1.0.0FFmpeg 播放器引擎ToolGood.Words3.0.3.1字幕繁简转换NLog5.2.0日志CommandLineParser、QueryString.NET、Win2D.uwp、Humanizer.Core.zh-CN等辅助库。同时项目引入了src/Shared/SharedAssemblyInfo.cs共享程序集信息并声明ViewModels.Uwp.rd.xmlUWP 反射元数据白名单保证源生成器产出的属性与命令在 .NET Native 编译下可被正确反射。视图模型层的编译依赖整体通过仓库根目录的 Uwp.props 统一配置如$(SolutionDir)\Uwp.props的导入与 App 工程src/App/App.csproj保持一致的 UWP 构建环境。七、总结视图模型层的分层范式从文档与源码可以归纳出 Bili.Uwp 视图模型层的三层范式页面视图模型层一个页面一个 VMVideoPlayerPageViewModel、BangumiPageViewModel、LivePlayerPageViewModel等只负责该页面的内容数据、筛选条件与列表状态通过Base目录下的领域基类复用信息流、PGC 页、关系页等共性逻辑功能模块视图模型层播放、字幕、弹幕、下载、互动选择、账户、导航等横切功能各自独立成 VM通过构造注入被页面或核心 VM 引用形成页面管内容、模块管能力的边界三大核心视图模型层AppViewModel应用级状态与全局动作中转、MediaPlayerViewModel播放中枢下辖字幕/弹幕/互动模块、NavigationViewModel三级导航与回退栈。这套体系在保证功能与视图分离的同时通过基类设施异常处理、加载退避、集合清理、命令状态回写统一了各 VM 的非功能性行为配合源生成器[ObservableProperty]/[RelayCommand]将样板代码降到最低是大型 UWP 客户端在 MVVM 落地时值得参考的工程范式。进一步阅读视图模型的接口定义与统一契约见 src/ViewModels/ViewModels.Interfaces其中包含IAppViewModel、IMediaPlayerViewModel、INavigationViewModel、ISubtitleModuleViewModel、IDanmakuModuleViewModel、IInformationFlowViewModel等三大核心的完整实现分别位于 Core/AppViewModel、Core/MediaPlayerViewModel、Core/NavigationViewModel播放器底层弹幕渲染、字幕解析等可继续参考 src/Lib/FrostMaster.Uwp 与 src/Lib/Lib.Implementation 中对应 Provider 的实现。赞分享音视频桌面应用【免费下载链接】Bili.Uwp适用于新系统UI的哔哩项目地址https://gitcode.com/GitHub_Trending/bi/Bili.Uwp点击查看免费下载相关推荐10个让电路搭建效率翻倍的BOOLR进阶快捷键撤销、Waypoint与选择框10个让电路搭建效率翻倍的BOOLR进阶快捷键撤销、Waypoint与选择框 BOOLR是一款免费开源的数字逻辑仿真器你可以在无限画布上拖拽逻辑门、连线搭建探索SwiftUI架构模型视图、Redux与ViewModel MVVM探索SwiftUI架构模型视图、Redux与ViewModel MVVM 在这个开放源代码项目中开发者们可以找到一个名为QBChat的简单聊天客户端的实现如何快速上手Microsoft PDB从零开始理解符号调试信息如何快速上手Microsoft PDB从零开始理解符号调试信息 想要在Windows平台上进行高效的C程序调试吗Microsoft PDBProgra上一篇PostHog ReviewHog 架构决策实录为何评论解决Resolution是独立的 Temporal Workflow 而非 Review 的一个阶段下一篇CANN PyPTO 向量编程范式 vf.reduce_max寄存器内最大值归约的语义、datablock 模式与源码级实现解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考