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

ACPF UI 框架设计与基础实现

世态人情,比明月清风更饶有滋味;可作书读,可当戏看。书上的描摹,戏里的扮演,即使栩栩如生,究竟只是文艺作品;人情世态,都是天真自然的流露,往往超出情理之外,新奇得令人震惊,令人骇怪,给人以更深刻的效益,更奇妙的娱乐。惟有身处卑微的人,最有机缘看到世态人情的真相,而不是面对观众的艺术表演。

—— 杨绛

一、ACPF UI 简介

Awesome Chrome Presentation Foundation UI:简称 ACPF UI,基于 CefSharp 库进行插件化封装,它提供接口的默认实现(预设)和常用 Attribute 特性(注解),开发者可以开箱即用,无需过多配置即可使用 Web 技术快速构建一个桌面应用。

应用场景:WPF 嵌入式浏览器解决方案。

该框架的核心是:通过解耦来简化配置,降低开发难度。例如,类似于 SpringBoot 通过注解实现依赖注入和控制反转等功能,ACPF UI 提供 Attribute 实现同样的效果,从而提高应用程序的灵活性和可维护性。

如果您想使用 Vue 等前端技术栈构建 WPF 桌面应用,并且使用的是 CefSharp 实现,那么您可以考虑使用 ACPF UI。

如果该框架并不能为您提供解决方案,请考虑使用其他成熟框架例如 Electron/Tauri/WinFormium 等。

二、ACPF 插件模块

安装 CefSharp.Wpf ,这里使用的版本是 119.1.20,

三、Attribute 特性

JavascriptObjectAttribute 用于导出 .net 方法为 js 对象,其他 ConfigurationAttribute 用于注入对应的配置项,

1、JavascriptObjectAttribute

using System;namespace AwesomeChromePresentationFoundationUI.Attributes
{/// <summary>/// 该注解代表将类作为 JavascriptObject 导出/// </summary>[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]public class JavascriptObjectAttribute : Attribute{/// <summary>/// 名字,通常为驼峰命名/// </summary>public string Name { get; set; }}
}

2、BrowserConfigurationAttribute

using System;namespace AwesomeChromePresentationFoundationUI.Attributes
{/// <summary>/// 自定义 Browser 配置注解/// </summary>[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]public class BrowserConfigurationAttribute : Attribute{}
}

3、CefConfigurationAttribute 

using System;namespace AwesomeChromePresentationFoundationUI.Attributes
{/// <summary>/// 自定义 Cef 配置注解/// </summary>[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]public class CefConfigurationAttribute : Attribute{}
}

4、MainViewConfigurationAttribute 

using System;namespace AwesomeChromePresentationFoundationUI.Attributes
{/// <summary>/// 自定义 BaseForm 配置注解/// </summary>[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]public class MainViewConfigurationAttribute : Attribute{}
}

四、Reflections 反射

AttributeUtil 用于扫描自定义 Attribute 的类,

1、AttributeUtil

using System;
using System.Linq;
using System.Reflection;namespace AwesomeChromePresentationFoundationUI.Reflections
{public class AttributeUtil{/// <summary>/// 找到第一个带注解的类/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public static Type FindFirstAnnotatedClass<T>() where T : Attribute{return AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.IsClass && t.GetCustomAttribute<T>() != null).FirstOrDefault();}/// <summary>/// 找到第一个带注解的类/// </summary>/// <typeparam name="T"></typeparam>/// <typeparam name="S">继承自S类</typeparam>/// <returns></returns>public static Type FindFirstAnnotatedClass<T, S>() where T : Attribute{return AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.IsClass && t.GetCustomAttribute<T>() != null && typeof(S).IsAssignableFrom(t)).FirstOrDefault();}}
}

五、Interfaces 接口

提供接口,引导自定义接口实现,

1、IBrowserConfiger

using AwesomeChromePresentationFoundationUI.Configs;namespace AwesomeChromePresentationFoundationUI.Interfaces
{public interface IBrowserConfiger{BrowserConfiguration CreateCustomBrowserConfiguration();}
}

2、ICefConfiger

using AwesomeChromePresentationFoundationUI.Configs;namespace AwesomeChromePresentationFoundationUI.Interfaces
{public interface ICefConfiger{CefConfiguration CreateCustomCefConfiguration();}
}

3、IMainViewConfiger


using AwesomeChromePresentationFoundationUI.Configs;namespace AwesomeChromePresentationFoundationUI.Interfaces
{public interface IMainViewConfiger{MainViewConfiguration CreateCustomBaseFormConfiguration();}
}

4、IConfigurationExecuter


namespace AwesomeChromePresentationFoundationUI.Interfaces
{public interface IConfigurationExecuter{void Execute();}
}

5、CefConfigurationExecuter

using AwesomeChromePresentationFoundationUI.Configs;
using CefSharp;namespace AwesomeChromePresentationFoundationUI.Interfaces.Implements
{public class CefConfigurationExecuter : IConfigurationExecuter{public void Execute(){CefConfiguration configuration = DefaultICefConfiger.CreateCustomCefConfiguration();Cef.Initialize(configuration.CefSettings,performDependencyCheck: configuration.PerformDependencyCheck,browserProcessHandler: configuration.BrowserProcessHandler);}}
}

六、Configs 配置

提取一些必要配置项并设置默认值,

1、BrowserConfiguration

using AwesomeChromePresentationFoundationUI.Constants;namespace AwesomeChromePresentationFoundationUI.Configs
{public class BrowserConfiguration{/// <summary>/// 默认编码/// </summary>public string DefaultEncoding { get; set; }/// <summary>/// 加载 URL/// </summary>public string HomeUrl { get; set; }public BrowserConfiguration(){this.DefaultEncoding = SystemConstant.BROWSER_DEFAULT_ENCODING;this.HomeUrl = SystemConstant.BROWSER_DEFAULT_LOAD_URL;}}
}

2、CefConfiguration

using CefSharp;
using CefSharp.SchemeHandler;
using CefSharp.Wpf;
using System;
using System.IO;namespace AwesomeChromePresentationFoundationUI.Configs
{public class CefConfiguration{/// <summary>/// 默认前端文件夹/// </summary>private string _defaultFrontendFolderPath;public CefSettingsBase CefSettings { get; set; }public bool PerformDependencyCheck { get; set; }public IBrowserProcessHandler BrowserProcessHandler { get; set; }public CefConfiguration(){CreateDefaultFrontendFolderPath();// Pseudo code; you probably need more in your CefSettings also.var settings = new CefSettings(){Locale = "zh-CN",// Increase the log severity so CEF outputs detailed information, useful for debuggingLogSeverity = LogSeverity.Verbose,//By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist dataCachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefSharp\\Cache")};//Example of setting a command line argument//Enables WebRTC// - CEF Doesn't currently support permissions on a per browser basis see https://bitbucket.org/chromiumembedded/cef/issues/2582/allow-run-time-handling-of-media-access// - CEF Doesn't currently support displaying a UI for media access permissions////NOTE: WebRTC Device Id's aren't persisted as they are in Chrome see https://bitbucket.org/chromiumembedded/cef/issues/2064/persist-webrtc-deviceids-across-restartsettings.CefCommandLineArgs.Add("enable-media-stream");//https://peter.sh/experiments/chromium-command-line-switches/#use-fake-ui-for-media-streamsettings.CefCommandLineArgs.Add("use-fake-ui-for-media-stream");//For screen sharing add (see https://bitbucket.org/chromiumembedded/cef/issues/2582/allow-run-time-handling-of-media-access#comment-58677180)settings.CefCommandLineArgs.Add("enable-usermedia-screen-capturing");//Disable GPU Accelerationsettings.CefCommandLineArgs.Add("disable-gpu");// Don't use a proxy server, always make direct connections. Overrides any other proxy server flags that are passed.// Slightly improves Cef initialize time as it won't attempt to resolve a proxysettings.CefCommandLineArgs.Add("no-proxy-server");settings.RegisterScheme(new CefCustomScheme{SchemeName = "http",DomainName = "yushanma.acpf",SchemeHandlerFactory = new FolderSchemeHandlerFactory(rootFolder: this._defaultFrontendFolderPath,hostName: "yushanma.acpf", //Optional param no hostname/domain checking if nulldefaultPage: "index.html") //Optional param will default to index.html});this.CefSettings = settings;this.PerformDependencyCheck = true;this.BrowserProcessHandler = null;}/// <summary>/// 创建默认前端文件夹/// </summary>private void CreateDefaultFrontendFolderPath(){string frontendFolderPath = Path.Combine(Directory.GetCurrentDirectory(), "Frontend");if (!Directory.Exists(frontendFolderPath)){Directory.CreateDirectory(frontendFolderPath);

相关文章:

  • 【Springboot】单元测试Junit5应用
  • 算法笔记刷题日记——3.简单入门模拟 3.1简单模拟
  • 合并分支rebase和merge的区别
  • 新手指南:Postman 旧版本(历史版本)下载
  • Unity类银河恶魔城学习记录1-12 PlayerComboAttack源代码 P39
  • js中原始类型和对象引用
  • 深入解析Elasticsearch的内部数据结构和机制:行存储、列存储与倒排索引之行存(一)
  • canvas设置图形各种混合模式,类似photoshop效果
  • 一篇文章了解系统眼中的键盘--以一个简单的系统分析从按键的输入到字符的显示
  • PyTorch中tensor.backward()函数的详细介绍
  • 微信小程序(三十三)promise异步写法
  • 从源代码看Chrome 版本号
  • 前后端分离,RSA加密传输方案
  • Vue学习笔记之组件基础
  • 基于STM32F103C8的宠物喂食系统设计
  • hexo+github搭建个人博客
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • HTML中设置input等文本框为不可操作
  • JS笔记四:作用域、变量(函数)提升
  • js中的正则表达式入门
  • MaxCompute访问TableStore(OTS) 数据
  • Python连接Oracle
  • vue从创建到完整的饿了么(11)组件的使用(svg图标及watch的简单使用)
  • Vue全家桶实现一个Web App
  • Vultr 教程目录
  • Webpack 4x 之路 ( 四 )
  • windows下使用nginx调试简介
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 开源SQL-on-Hadoop系统一览
  • 前端之Sass/Scss实战笔记
  • 入门到放弃node系列之Hello Word篇
  • 使用 QuickBI 搭建酷炫可视化分析
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 数据结构java版之冒泡排序及优化
  • 小程序button引导用户授权
  • 智能合约开发环境搭建及Hello World合约
  • 好程序员大数据教程Hadoop全分布安装(非HA)
  • #if #elif #endif
  • #预处理和函数的对比以及条件编译
  • $(selector).each()和$.each()的区别
  • (04)odoo视图操作
  • (2015)JS ES6 必知的十个 特性
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (Note)C++中的继承方式
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (三)mysql_MYSQL(三)
  • (实战篇)如何缓存数据
  • (四)库存超卖案例实战——优化redis分布式锁
  • (转)可以带来幸福的一本书
  • *p++,*(p++),*++p,(*p)++区别?
  • .NET Reactor简单使用教程
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • .NET牛人应该知道些什么(2):中级.NET开发人员