ACPF UI 框架设计与基础实现

news2024/11/28 19:29:47

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

—— 杨绛

一、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.coloradmin.cn/o/1432586.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python】python爱心代码【附源码】

一、实现效果&#xff1a; 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 二、完整代码&#xff1a; import math import random import threading import time from math import sin, cos, pi, log from tkinter import * import re# 烟花相关设置 Fireworks [] m…

离线下载安装postgresql12/13/14/15.

前言 参考此链接&#xff0c;但是有问题 1.下载离线rpm包 下载安装postgresql-devel 12以上版本&#xff0c;去postgresql下载官网&#xff0c;然后自己选择是pg12还是13、14、15等。&#xff08;我选的12&#xff09;。不想麻烦的直接去我这资源直接下载 下载这个五个文件&…

CHS_09.2.3.6_2+多生产者-多消费者

CHS_09.2.3.6_2多生产者-多消费者 问题描述问题分析如何实现如何实现假如我们把盘子的容量设为二知识回顾 在这个小节中 我们会学习一个多生产者 多消费者的这样一个问题模型 问题描述 先来看一下问题的描述 假设桌子上面有一个盘子 每次只能向这个盘子里放一个水果 有四个人…

SpringBoot 各种回滚骚操作实战

事务定义 事务&#xff0c;就是一组操作数据库的动作集合。事务是现代数据库理论中的核心概念之一。如果一组处理步骤或者全部发生或者一步也不执行&#xff0c;我们称该组处理步骤为一个事务。当所有的步骤像一个操作一样被完整地执行&#xff0c;我们称该事务被提交。由于其…

Leetcode高频题:198打家劫舍1

题目链接力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相…

力扣 121. 买卖股票的最佳时机

题目来源&#xff1a;https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/ 好久没写代码了&#xff0c;啥啥都忘了 C题解1&#xff1a;贪心算法。&#xff08;来源代码随想录&#xff09; 因为股票就买卖一次&#xff0c;那么贪心的想法很自然就是取…

拖拽按钮: 如何区分点击和拖拽事件 (vueuse实现)

问题&#xff1a;使用vueuse的useDraggable去拽按钮时会触发点击事件&#xff0c;即使设置阻止默认事件还是没用。 方案1&#xff1a;判断拖拽时长 判断拖拽时长&#xff0c;如果大于点击的时间秒数&#xff0c;则被认为是拖拽。小于被认为是点击&#xff0c;则触发点击事件…

【01】C++入门

文章目录 Ⅰ 命名空间1. 命名空间域的产生2. 命名空间域的定义3. 命名空间域的使用 Ⅱ 缺省参数1. 缺省的概念2. 缺省的分类3. 声明和定义不能同时存在缺省参数 Ⅲ 函数重载1. 函数重载概念2. 编译器如何实现函数重载 Ⅳ 引用1. 引用的概念2. 引用的特性3. 引用的使用场景4. 引…

【Go-Zero】Error: only one service expected goctl一键转换生成rpc服务错误解决方案

【Go-Zero】Error: only one service expected goctl一键转换生成rpc服务错误解决方案 大家好 我是寸铁&#x1f44a; 总结了一篇Error: only one service expected goctl一键转换生成rpc服务错误解决方案的文章✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 问题背景 今天寸铁在…

Qt之使用Qt内置图标

一效果 二.原理 Qt内置图标封装在QStyle中,共七十多个图标,可以直接拿来用,能应付不少简单程序需求,不用自己去找图标并添加到资源文件了。 下面是内置图标的枚举定义: enum StandardPixmap {SP_TitleBarMenuButton,SP_TitleBarMinButton,SP_TitleBarMaxButton,SP_T…

[Python] scikit-learn中数据集模块介绍和使用案例

sklearn.datasets模块介绍 在scikit-learn中&#xff0c;可以使用sklearn.datasets模块中的函数来构建数据集。这个模块提供了用于加载和生成数据集的函数。 API Reference — scikit-learn 1.4.0 documentation 以下是一些常用的sklearn.datasets模块中的函数 load_iris() …

真是令人震惊!都已经2024年了,居然在撸货圈里还存在收徒的现象?

前不久发现了京东淘宝的正确购买方式之后 才明白一直想买的东西其实没有想象中的那么贵 而且这种购买方式谁都可以学会 首先要了解平台的规则和购买的方法&#xff01;才能顺利买到&#xff01;不然你看到了漏洞也不会撸&#xff0c;就看别人上车&#xff01; 1.首先你要加…

你所不知道的关于库函数和系统调用的那些事

系统调用和库函数的区别 相信大家在面试或者刷面试题的时候经常能看到这样的问题&#xff0c;“简述一下系统调用和库函数的区别”。 系统调用是操作系统提供给用户的接口&#xff0c;能让用户空间的程序有入口访问内核。而库函数数一组标准函数&#xff0c;比如复合 POSIX 或…

【论文笔记】Lift-Attend-Splat: Bird’s-eye-view camera-lidar fusion using transformers

原文链接&#xff1a;https://arxiv.org/abs/2312.14919 1. 引言 多模态融合时&#xff0c;由于不同模态有不同的过拟合和泛化能力&#xff0c;联合训练不同模态可能会导致弱模态的不充分利用&#xff0c;甚至会导致比单一模态方法性能更低。 目前的相机-激光雷达融合方法多基…

react将选中本文自动滑动到容器可视区域内

// 自动滚动到可视区域内useEffect(() > {const target ref;const wrapper wrapperRef?.current;if (target && wrapperRef) {const rect target.getBoundingClientRect();const wrapperRect wrapper.getBoundingClientRect();const isVisible rect.bottom &l…

Vision Transfomer系列第一节---从0到1的源码实现

本专栏主要是深度学习/自动驾驶相关的源码实现,获取全套代码请参考 这里写目录标题 准备逐步源码实现数据集读取VIt模型搭建hand类别和位置编码类别编码位置编码 blocksheadVIT整体 Runner(参考mmlab)可视化 总结 准备 本博客完成Vision Transfomer(VIT)模型的搭建和flowers数…

2024机械工程师面试题

1.常用的机械画图软件有哪些 SolidWorks、Pro/e、CATIA、UG、Creo、CAD、inventor。CAXA电子图板. 2.第一视角是___&#xff0c;第三视角是___&#xff1b; 只要区别是&#xff1a;物体所处的位置不同。一般中国都使用第一视角的。 3.气缸属于_____执行元件&#xff0c;电磁…

Multisim14.0仿真(五十一)基于LM555定时器的分频器设计

一、1KHz脉冲设置&#xff1a; 二、555脉冲电路&#xff1a; 三、仿真电路&#xff1a; 四、运行仿真&#xff1a;

【Linux笔记】缓冲区的概念到标准库的模拟实现

一、缓冲区 “缓冲区”这个概念相信大家或多或少都听说过&#xff0c;大家其实在C语言阶段就已经接触到“缓冲区”这个东西&#xff0c;但是相信大家在C语言阶段并没有真正弄懂缓冲区到底是个什么东西&#xff0c;也相信大家在C语言阶段也因为缓冲区的问题写出过各种bug。 其…

【计算机视觉】万字长文详解:卷积神经网络

以下部分文字资料整合于网络&#xff0c;本文仅供自己学习用&#xff01; 一、计算机视觉概述 如果输入层和隐藏层和之前一样都是采用全连接网络&#xff0c;参数过多会导致过拟合问题&#xff0c;其次这么多的参数存储下来对计算机的内存要求也是很高的 解决这一问题&#x…