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);
     
  • 16
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

余衫马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值