当前位置: 首页 > article >正文

WPF-Control核心架构思想

WPF-Control 项目架构详解一、核心架构思想这个项目的架构可以用一句话概括控件负责显示服务负责能力模块负责组合主题负责外观ApplicationBase 负责生命周期IOC 负责连接所有对象。这是一种典型的分层模块化架构各个组件职责清晰松耦合易于扩展和维护。二、分层关系详解2.1 分层架构图┌─────────────────────────────────────────────────────────────┐ │ App / Tests │ ← 应用入口/测试层 ├─────────────────────────────────────────────────────────────┤ │ ApplicationBase │ ← 生命周期管理 ├─────────────────────────────────────────────────────────────┤ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ IOC │ │ Services │ │ Modules │ │ ← 核心服务层 │ └──────────┘ └──────────┘ └──────────┘ │ ├─────────────────────────────────────────────────────────────┤ │ Themes / Styles / Controls / Presenters │ ← UI展示层 └─────────────────────────────────────────────────────────────┘2.2 各层职责说明层级职责典型文件/组件App应用入口继承ApplicationBaseApp.xaml.csApplicationBase生命周期管理、异常处理、启动流程ApplicationBase.csIOC依赖注入容器连接所有对象Ioc.cs,IocExtension.csServices提供各种业务能力数据库、日志、消息等ILogService,IMessageServiceModules功能模块组合封装业务单元HomeBox,ProjectModuleThemes/Styles外观样式管理Generic.xaml,Share.xamlControls/PresentersUI控件和视图逻辑TagBox,HomeViewPresenter三、运行流程剖析3.1 完整启动流程启动 App │ ├─→ 创建 ServiceCollection (DI容器构建) │ ├─→ ConfigureServices 注册模块和服务 │ ├─→ Ioc.Build 构建容器 │ ├─→ 加载多语言 (ILoadGlobalizationOptionsService) │ ├─→ Configure 应用配置 │ ├─→ 加载主题 (ILoadThemeOptionsService) │ ├─→ 显示启动页 (SplashScreen) │ ├─→ 执行登录 (ILoginViewPresenter) │ ├─→ 创建并显示主窗口 │ └─→ 用户操作控件 → Command / Presenter / Service 响应3.2 核心流程代码解析第一步应用启动入口publicpartialclassApp:ApplicationBase{protectedoverridevoidConfigureServices(IServiceCollectionservices){// 注册应用服务services.AddApplicationServices();// 注册项目服务services.AddProjectAIDIProjectService(xx.UseOpenCurrentOnLoadfalse);// 注册模块services.AddHomeProjectThumbnialHomeViewPresenter();// 注册标签服务services.AddTagProjectTagService(x{x.Tags.Add(newTag(){Name训练数据,BackgroundBrushes.Green});x.Tags.Add(newTag(){Name测试数据,BackgroundBrushes.Gray});});// 注册数据库services.AddDbContextBySettingAIDIDataContext();services.AddSingletonIStringRepositoryfm_dd_image,DbContextRepositoryAIDIDataContext,fm_dd_image();}protectedoverrideWindowCreateMainWindow(StartupEventArgse){returnnewMainWindow();}}关键要点ConfigureServices方法用于注册所有服务和模块使用扩展方法链式调用代码清晰优雅支持配置回调可在注册时进行初始化配置第二步ApplicationBase 初始化publicabstractpartialclassApplicationBase:Application{publicApplicationBase(){this.ShutdownModeShutdownMode.OnMainWindowClose;AppPaths.Register(this.CreateAppPathServce());this.InitExcetion();// 初始化异常处理this.InitServiceCollection();// 初始化服务容器}protectedvoidInitServiceCollection(){ServiceCollectionscnewServiceCollection();this.ConfigureServices(sc);// 调用子类的配置Ioc.Build(sc);// 构建IOC容器// 在显示页面前加载多语言Ioc.GetServiceILoadGlobalizationOptionsService(false)?.Load(outstringmessage);}}关键要点构造函数执行顺序异常处理 → 服务注册 → 多语言加载Ioc.Build(sc)是核心将所有服务注册到容器第三步OnStartup 启动流程protectedoverridevoidOnStartup(StartupEventArgse){this.Configure();// 应用配置this.OnSingleton(e);// 单例检查base.OnStartup(e);Windowwindowthis.CreateMainWindow(e);// 主窗口加载完成后执行window.Loaded(s,e){varloadsIoc.GetAssignableFromServicesIMainWindowLoadedLoadable().Distinct();foreach(variteminloads)item.Load(outstringmessage);};this.OnSplashScreen(e);// 显示启动页this.OnLogin();// 执行登录IocIMainWindowSavableService.Instance?.Load(window);this.MainWindow.Show();}关键要点启动流程配置 → 单例检查 → 启动页 → 登录 → 主窗口通过Ioc.GetAssignableFromServicesT()实现批量服务调用四、核心组件详解4.1 IOC 容器IOC控制反转是整个架构的核心连接器负责管理所有对象的创建和依赖注入。publicstaticclassIoc{privatestaticIServiceProvider_servicesnull;publicstaticIServiceProviderServices_services;publicstaticvoidBuild(IServiceCollectionserviceCollection){_servicesserviceCollection.BuildServiceProvider();}publicstaticTGetServiceT(boolthrowIfNonetrue){if(_servicesnull)returnthrowIfNone?thrownewArgumentNullException(...):default;returnGetServiceT(typeof(T),throwIfNone);}// 通过类型获取服务publicstaticTGetServiceT(Typetype,boolthrowIfNonetrue){Tr(T)_services.GetService(type);if(rnullthrowIfNone)thrownewArgumentNullException(...);returnr;}// 获取所有实现了某个接口的服务publicstaticIEnumerableTGetAssignableFromServicesT(FuncT,boolpredicatenull){foreach(ServiceDescriptoritemin_serviceCollection){if(typeof(T).IsAssignableFrom(item.ServiceType)){// 遍历所有符合条件的服务实例...}}}}IOC 使用场景场景代码示例获取单例服务Ioc.GetServiceILogService()安全获取不抛异常Ioc.GetServiceIMyService(false)获取多个服务Ioc.GetAssignableFromServicesISplashLoadable()XAML 绑定IocExtension Type{x:Type local:MyService} /4.2 ApplicationBase 生命周期ApplicationBase封装了 WPF 应用的完整生命周期构造函数 │ ├─→ InitExcetion() // 注册异常处理 │ ├─→ DispatcherUnhandledException │ ├─→ AppDomain.UnhandledException │ └─→ TaskScheduler.UnobservedTaskException │ └─→ InitServiceCollection() ├─→ 创建 ServiceCollection ├─→ ConfigureServices() └─→ Ioc.Build() OnStartup │ ├─→ Configure() // 应用配置 ├─→ OnSingleton() // 单例检查 ├─→ OnSplashScreen() // 启动页 ├─→ OnLogin() // 登录 └─→ Show MainWindow OnExit │ ├─→ 停止定时任务 ├─→ 记录退出日志 └─→ 保存操作记录4.3 模块系统模块是功能的封装单元通过扩展方法注册publicstaticclassExtension{publicstaticIServiceCollectionAddHomeT(thisIServiceCollectionservices,ActionIHomeOptionssetupActionnull)whereT:class,IHomeViewPresenter{services.AddOptions();services.TryAdd(ServiceDescriptor.SingletonIHomeViewPresenter,T());if(setupAction!null)services.Configure(newActionHomeOptions(setupAction));returnservices;}}模块注册模式定义接口如IHomeViewPresenter实现具体类如ProjectThumbnialHomeViewPresenter通过扩展方法注册到 IOC在需要的地方通过接口获取实例五、项目结构实践5.1 推荐的项目目录结构Source/ ├── App/ # 应用程序 │ └── H.App.AIDI/ # 具体应用 │ ├── App.xaml.cs # 入口 │ ├── MainWindow.xaml # 主窗口 │ └── ViewModel/ # 视图模型 ├── Base/ # 基础组件 │ ├── H.Attach/ # 附加属性 │ └── H.Mvvm/ # MVVM框架 ├── Controls/ # 自定义控件 │ ├── H.Controls.TagBox/ # 标签控件 │ └── H.Controls.Form/ # 表单控件 ├── Modules/ # 功能模块 │ └── H.Modules.Home/ # 首页模块 ├── Providers/ # 服务提供者 │ └── H.Iocable/ # IOC容器 ├── Services/ # 服务层 │ └── H.Services.Common/ # 公共服务 └── Styles/ # 样式主题 └── H.Style/ # 全局样式5.2 创建新模块的步骤假设我们要创建一个设置模块步骤1定义接口publicinterfaceISettingViewPresenter:IViewPresenter{voidShow();}步骤2实现 PresenterpublicclassSettingViewPresenter:ISettingViewPresenter{publicvoidShow(){// 显示设置窗口逻辑}}步骤3创建扩展方法publicstaticclassSettingExtension{publicstaticIServiceCollectionAddSetting(thisIServiceCollectionservices){services.TryAddSingletonISettingViewPresenter,SettingViewPresenter();returnservices;}}步骤4在 App 中注册protectedoverridevoidConfigureServices(IServiceCollectionservices){services.AddSetting();}步骤5使用模块Ioc.GetServiceISettingViewPresenter().Show();六、最佳实践总结6.1 设计原则单一职责每个类只做一件事控件只负责显示服务只提供能力依赖倒置依赖抽象而非具体实现接口隔离使用细粒度接口避免胖接口开闭原则对扩展开放对修改关闭6.2 代码规范// ✅ 推荐依赖接口publicclassMyPresenter{privatereadonlyILogService_logService;publicMyPresenter(ILogServicelogService){_logServicelogService;}}// ❌ 不推荐依赖具体类publicclassMyPresenter{privatereadonlyLogService_logServicenewLogService();}6.3 服务注册规范生命周期使用场景注册方式Singleton全局共享服务日志、配置AddSingletonScoped每个请求/窗口独立AddScopedTransient每次获取新实例AddTransient七、总结WPF-Control 的架构设计体现了以下核心价值高内聚低耦合各层职责清晰模块独立可扩展性强通过 IOC 和接口实现松耦合扩展易于测试依赖注入使单元测试更简单统一生命周期ApplicationBase 统一管理应用生命周期通过理解这个架构模式您可以快速上手项目开发按照规范创建新模块高效定位和解决问题参与项目贡献

相关文章:

WPF-Control核心架构思想

WPF-Control 项目架构详解 一、核心架构思想 这个项目的架构可以用一句话概括:控件负责显示,服务负责能力,模块负责组合,主题负责外观,ApplicationBase 负责生命周期,IOC 负责连接所有对象。这是一种典型的…...

别再到处找汉化包了!PowerDesigner 15.1 保姆级安装与汉化教程(附资源)

PowerDesigner 15.1 完整安装与汉化实战指南 对于数据库设计领域的初学者和专业开发者来说,PowerDesigner无疑是一款功能强大的建模工具。然而,英文界面常常成为非英语母语用户的第一道门槛。本文将提供一份从零开始的完整解决方案,涵盖软件安…...

新手PM如何快速成长?一套可落地的自我迭代复盘方法

新手 PM 想快速成长,不能只靠多做几个项目,更要学会从每个项目里复盘经验、发现问题、沉淀方法。尤其是从市场、运营、业务等岗位转型做项目经理的人,更需要通过复盘提升需求管理、进度管理和团队协作能力。本文分享一套适合项目经理新人的自…...

OBS智能跟拍插件:3分钟实现直播自动追踪的终极指南

OBS智能跟拍插件:3分钟实现直播自动追踪的终极指南 【免费下载链接】obs-face-tracker Face tracking plugin for OBS Studio 项目地址: https://gitcode.com/gh_mirrors/ob/obs-face-tracker 您是否在直播时经常为手动调整摄像头而烦恼?是否希望…...

ARM DesignStart免费开放Cortex-M0/M3内核,开启零门槛定制SoC时代

1. 项目概述:ARM DesignStart升级,工程师的“零门槛”造芯时代作为一名在嵌入式领域摸爬滚打了十几年的老工程师,我亲眼见证了芯片设计从大型公司的“专利”到如今工程师个人也能触及的转变。最近,ARM公司对其DesignStart项目的一…...

风云三国2.4问鼎天下:不靠作弊代码,用TXT文件修改实现俘虏名将和强制投降

风云三国2.4问鼎天下:TXT文件修改实现俘虏名将与强制投降的硬核技巧 在《风云三国2.4问鼎天下》这款经典MOD中,许多玩家都渴望能够招降那些赫赫有名的武将,比如关羽、诸葛亮等,但游戏机制往往让这些名将难以归顺。传统的作弊代码虽…...

谷歌搜索重大更新:更智能个性化,多项新功能即将上线!

谷歌搜索迈向更智能、更个性化时代曾几何时,谷歌搜索简洁易用,只需在搜索框输入关键词,浏览蓝色链接列表即可。然而,如今人工智能已层层覆盖搜索模式。2026 年谷歌 I/O 大会上,谷歌宣布一系列搜索更新,使搜…...

从门电路到芯片:拆解一个D触发器,看数字电路如何实现‘记忆’这个核心功能

从门电路到芯片:拆解一个D触发器,看数字电路如何实现‘记忆’这个核心功能 数字世界的每一个比特信息都需要被精确存储和传递,而实现这一功能的核心元件便是触发器。当我们按下电脑的电源键,屏幕上闪现的第一个像素到硬盘中保存的…...

别再死记硬背了!用Python写个语法分析器,帮你彻底搞懂英语非谓语动词

用Python构建英语非谓语动词分析器:从语法规则到代码逻辑 引言:当编程遇上英语语法 英语学习中最令人头疼的部分莫过于非谓语动词——那些不做谓语的动词形式,包括不定式、分词和动名词。传统学习方法要求死记硬背各种规则和例外,…...

从STM32转战合泰HT32F52352:手把手教你用GPTM定时器搞定四路舵机PWM控制

从STM32到HT32F52352的平滑迁移:GPTM定时器实现四路舵机PWM控制实战 对于习惯了STM32生态的开发者而言,初次接触合泰HT32系列MCU时往往面临两个挑战:如何快速理解新芯片的架构设计,以及如何将已有的STM32开发经验有效迁移。HT32F…...

LVGL 8.x 实战:搞定Label点击、背景色和文字对齐的3个高频难题

LVGL 8.x实战:攻克Label交互、样式与布局的三大核心痛点 在嵌入式UI开发领域,LVGL以其轻量级和高度可定制性成为众多开发者的首选。但当我们真正开始构建第一个界面时,往往会遇到一些看似简单却令人抓狂的问题——为什么Label不能点击&#…...

正交试验结果怎么看?一张图教你读懂SPSSAU的极差分析表和均值图

正交试验结果解读指南:从极差分析到最优组合决策 正交试验作为多因素优化研究的利器,其价值往往在数据解读阶段才能真正释放。当SPSSAU输出的极差分析表和均值图呈现在眼前时,许多研究者会陷入"数字迷宫"——那些K1/K2/K3值究竟在诉…...

别再纠结IO口了!手把手教你用三极管实现RS485自动收发(附电路图与阻值计算)

三极管驱动RS485自动收发电路设计实战指南 在嵌入式系统开发中,RS485通信因其抗干扰能力强、传输距离远等优势被广泛应用。然而传统RS485电路需要额外GPIO控制收发方向,当面临IO资源紧张或底层驱动不可控时,硬件工程师常陷入两难境地。本文将…...

ABAP 7.40+新语法实战:5个内表处理技巧让你告别LOOP和IF

ABAP 7.40新语法实战:5个内表处理技巧让你告别LOOP和IF 在SAP开发领域,ABAP语言随着7.40版本的发布迎来了一次重大革新。对于每天需要处理大量内表操作的中级开发者来说,这些新特性不仅能显著减少代码量,更能提升程序的可读性和执…...

Ansys Zemax实战:用Zernike相位面给离轴反射镜‘加料’,模拟加工误差就这么简单

Ansys Zemax高阶技巧:Zernike相位面在离轴反射镜公差分析中的工程实践 在光学系统设计领域,公差分析是确保量产可行性的关键环节。当设计从理想状态走向实际制造时,加工误差、装配偏差等因素都会对系统性能产生影响。对于离轴反射镜这类非对称…...

功能安全计划:从ISO 26262到IEC 61508的系统性工程实践

1. 项目概述:为什么我们需要一个“功能安全计划”?在汽车和工业领域,一个简单的软件Bug或硬件失效,其后果可能远超一次蓝屏或服务中断。想象一下,一辆高速行驶的汽车,其电子稳定程序(ESP&#x…...

如何用Vibe coding一周做三个成果?(附完整prompt) 【新手友好】

最近AI圈刮起了一阵"Vibe coding"旋风,很多朋友私信问我:到底什么是Vibe coding?零基础真的能学会吗?一周真的能做出好几个可以用的成果吗?作为亲身体验了一把的人,我可以明确告诉大家&#xff1…...

嵌入式AI转型实战:从传统MCU开发到端侧智能部署

1. 项目概述:当嵌入式遇上AI,一场静默的变革最近和几个在芯片原厂、消费电子和工业控制领域干了十多年的老伙计聊天,话题总绕不开一个词:AI。不是那种高谈阔论的未来畅想,而是实实在在的焦虑和困惑。一个做电机驱动的兄…...

Unity URP专业UI模糊效果实战指南:4步实现高性能毛玻璃界面

Unity URP专业UI模糊效果实战指南:4步实现高性能毛玻璃界面 【免费下载链接】Unified-Universal-Blur UI blur (translucent) effect for Unity. 项目地址: https://gitcode.com/gh_mirrors/un/Unified-Universal-Blur 在Unity游戏开发中,UI界面的…...

OpenStack部署避坑实录:从网络不通到Dashboard白屏,我踩过的那些‘坑’及解决办法

OpenStack部署避坑指南:从时间同步到Dashboard白屏的实战解决方案 部署OpenStack云平台时,即使按照官方文档一步步操作,也难免会遇到各种"坑"。本文将分享我在实际部署过程中遇到的五个典型问题及其解决方案,帮助你在遇…...

从“收音机”到“手机芯片”:聊聊CMOS单级放大器在真实产品里的那些事儿

从“收音机”到“手机芯片”:CMOS单级放大器的工业进化史 上世纪60年代,当第一台全晶体管收音机问世时,工程师们或许不会想到,那些分立元件组成的放大器电路,有朝一日会以纳米级尺寸被集成在指甲盖大小的芯片里。CMOS单…...

保姆级教程:用Arduino IDE从零配置ESP32-CAM,5分钟搞定网络摄像头

零基础玩转ESP32-CAM:5分钟搭建智能网络摄像头的完整指南 第一次拿到ESP32-CAM这块小巧的开发板时,很多人都会被它丰富的功能所吸引——Wi-Fi连接、摄像头拍摄、甚至还能进行简单的人脸识别。但当你真正开始尝试用它搭建一个网络摄像头时,各种…...

终极LXMusic音源配置指南:三步解决全网音乐播放难题

终极LXMusic音源配置指南:三步解决全网音乐播放难题 【免费下载链接】LXMusic音源 lxmusic(洛雪音乐)全网最新最全音源 项目地址: https://gitcode.com/guoyue2010/lxmusic- 你是否经常遇到音乐软件资源不全、音质不佳的问题&#xff…...

嵌入式开发工具演进:从传统IDE到多核AI系统协同平台

1. 嵌入式开发工具的演进:从“编译助手”到“系统协作者”干了十几年嵌入式,从51单片机玩到现在的多核异构AI SoC,我最大的感受就是:手里的家伙事儿,越来越跟不上趟了。早些年,一个IDE(集成开发…...

docker启动线程创建异常 pthread_create EPERM | RuntimeError: can‘t start new thread

直接说答案,着急就复制过去使用 docker配置 增加对应权限配置参数即可 --privileged 如果上述不行,docker配置 使用组合方式 --privileged \ --ulimit nproc65535:65535 \ --ulimit nofile65535:65535 \详细解释 下面逐项解释这些 Docker 参数的作用、…...

Unity事件(Event)实战避坑:从金币系统到UI更新,我踩过的3个坑和解决方案

Unity事件系统实战避坑指南:从金币系统到UI更新的3个典型问题解析 在Unity开发中,事件系统是实现模块间解耦的利器,但新手往往会遇到各种"诡异"的问题。本文将聚焦一个金币收集与UI更新的实际案例,深入分析三个最常见的…...

收藏!AI时代,软件工程基本功才是你的核心竞争力

在AI coding时代,软件工程的基本功不仅没有过时,反而比以往任何时候都更加重要。AI是放大器,好的代码库能提升效率,而模糊混乱的代码库则会放大混乱。接口、边界、领域语言和测试等“老派”的基本功,是开发者手中杠杆率…...

观察不同模型在Taotoken平台上的实际响应速度与效果差异

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 观察不同模型在Taotoken平台上的实际响应速度与效果差异 在开发与创作过程中,我们常常需要调用大模型API来完成文本生成…...

避开FPGA除法器设计的那些‘坑’:恢复余数 vs. 不恢复余数 vs. SRT 实战选型指南

FPGA除法器设计实战:恢复余数、不恢复余数与SRT算法选型指南 在数字信号处理、图形渲染或科学计算等FPGA应用中,除法运算往往是性能瓶颈所在。不同于乘法器可通过流水线大幅提速,除法器的设计需要工程师在算法选择阶段就做出关键决策——恢复…...

告别PS!用ImageMagick命令行5分钟搞定100张图片格式批量转换(附Windows/Mac安装避坑)

告别PS!用ImageMagick命令行5分钟搞定100张图片格式批量转换(附Windows/Mac安装避坑) 在数字内容爆炸式增长的今天,图片处理已成为开发者、设计师和内容运营人员的日常刚需。当面对上百张需要统一转换格式、调整尺寸的图片时&…...