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

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 debugging
                LogSeverity = LogSeverity.Verbose,
                //By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data
                CachePath = 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-restart
            settings.CefCommandLineArgs.Add("enable-media-stream");
            //https://peter.sh/experiments/chromium-command-line-switches/#use-fake-ui-for-media-stream
            settings.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 Acceleration
            settings.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 proxy
            settings.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 null
                            defaultPage: "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);
        

http://www.kler.cn/a/227943.html

相关文章:

  • 【自学嵌入式(7)天气时钟:WiFi模块、OLED模块、NTP模块开发】
  • Docker小游戏 | 使用Docker部署FC-web游戏模拟器
  • 数仓ETL测试
  • AI在自动化测试中的伦理挑战
  • JavaScript - Web APIs(下)
  • 【python】subprocess.Popen执行adb shell指令进入linux系统后连续使用指令,出现cmd窗口阻塞问题
  • iOS图像处理----OpenGL ES之灰色滤镜
  • Node.js 包管理工具
  • Adobe Camera Raw for Mac v16.1.0中文激活版
  • 基于JavaWeb开发的火车售票系统[附源码]
  • 网络编程面试系列-01
  • 【React】redux状态管理、react-redux状态管理高级封装模块化
  • react 之 zustand
  • day19 初始HTML
  • 两种方式实现文本超出指定行数显示展开收起...
  • PyTorch 2.2 中文官方教程(八)
  • [设计模式Java实现附plantuml源码~结构型]处理多维度变化——桥接模式
  • 总结了一下中继引擎(can中继器,TCP总机器)开发实际经验
  • 【PDF.js】发票PDF不显示文本的问题
  • PyTorch 2.2 中文官方教程(四)
  • 移动端基础-vw适配
  • 用GOGS搭建GIT服务器
  • vue3学习——mock数据
  • SpringCloud-Eureka
  • 07、全文检索 -- Solr -- Solr 全文检索 之 为索引库添加中文分词器
  • Redis——SpringBoot整合Redis实战