Winform NanUI 0.77版本 读取本地资源(扩展功能)

本文档介绍了如何在NanUI 0.77版本中搭建环境并实现自定义资源处理器,包括将源码集成到项目、处理资源报错、注册资源处理器等步骤。通过新建`CustomResourceFactory`和`CustomResourceHandler`类,实现了从本地文件系统读取资源的功能。此外,还提供了提高资源读取速度的方法。文章适合已经对NanUI有一定了解,并希望进行扩展的开发者阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

在NanUI官方的文档中,原本是有一个NanUI.FileResourceHandler的扩展包的,但现在官方已经无法下载了,现在只有0.88版本中有一个NanUI.LocalFileResource程序包,而0.77版本只剩下了一个读取嵌入式资源的程序包。

关于NanUI:NanUI | .Net/.Net Core界面组件NanUI 0.7版正式发布 - 林选臣 - 博客园

在扩展功能之前,请参考[资源处理器]-04 自定义资源处理器 - 知乎 ,我参考这个帖子进行扩展的,也不知道改的对不对,总之功能是实现了。

二、搭建环境

将NanUI0.77源码拷贝到你的项目中,将源码中的Resources.Designer.cs代码复制到你项目中的Resources.Designer.cs 中,

Resources.Designer.cs 中要加入的代码:

/// <summary>
///   查找类似于 (图标) 的 System.Drawing.Icon 类型的本地化资源。
/// </summary>
internal static System.Drawing.Icon DevToolsIcon {
    get {
        object obj = ResourceManager.GetObject("DevToolsIcon", resourceCulture);
        return ((System.Drawing.Icon)(obj));
    }
}

/// <summary>
///   查找类似 var NanUI = NanUI || {};
///
///(function(target) {
///  const CMD_ATTR_PREFIX = &quot;nanui-command&quot;;
///
///  const RAISE_FUNC_NAME = &quot;__nanui_raiseHostWindowEvent&quot;;
///
///  const GLOBAL_CLICK_HANDLER_REGISTERED =
///    &quot;__nanui_global_click_handler_registered&quot;;
///
///  if (!window.hasOwnProperty(RAISE_FUNC_NAME)) {
///    window[RAISE_FUNC_NAME] = function(eventName, data) {
///      window.dispatchEvent(new CustomEvent(eventName, { detail: data }));
///    };
///  }
///
///  if (!(GLOBAL_CLICK_HANDLER_REGISTERED in window)) {
///    windo [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary>
internal static string FrameGlobalRegistrationScript {
    get {
        return ResourceManager.GetString("FrameGlobalRegistrationScript", resourceCulture);
    }
}

/// <summary>
///   查找类似 var NanUI = NanUI || {};
///
///(function (target) {
///    var hostWindow = {
///        minimize: function () {
///            native function Minimize();
///            return Minimize();
///        },
///        maximize: function () {
///            native function Maximize();
///            return Maximize();
///        },
///        restore: function () {
///            native function Restore();
///            return Restore();
///        },
///        close: function () {
///            native function Close();
///            return  [字符串的其余部分被截断]&quot;; 的本地化字符串。
/// </summary>
internal static string HostWindowExtension {
    get {
        return ResourceManager.GetString("HostWindowExtension", resourceCulture);
    }
}

/// <summary>
///   查找类似                                             
///  P.O.W.E.R.E.D BY                          
///  ███╗   ██╗ █████╗ ███╗   ██╗██╗   ██╗██╗  
///  ████╗  ██║██╔══██╗████╗  ██║██║   ██║██║  
///  ██╔██╗ ██║███████║██╔██╗ ██║██║   ██║██║  
///  ██║╚██╗██║██╔══██║██║╚██╗██║██║   ██║██║  
///  ██║ ╚████║██║  ██║██║ ╚████║╚██████╔╝██║  
///  ╚═╝  ╚═══╝╚═╝  ╚═╝╚═╝  ╚═══╝ ╚═════╝ ╚═╝  
///                            S.I.N.C.E 2016  
///                                             的本地化字符串。
/// </summary>
internal static string nanui {
    get {
        return ResourceManager.GetString("nanui", resourceCulture);
    }
}

/// <summary>
///   查找类似 var NanUI = NanUI || {};
///
///(function (target) {
///
///  target.__defineGetter__(&quot;version&quot;, function () {
///    native function Version();
///    return Version();
///  });
///  
///})(NanUI); 的本地化字符串。
/// </summary>
internal static string NanUIExtension {
    get {
        return ResourceManager.GetString("NanUIExtension", resourceCulture);
    }
}

/// <summary>
///   查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap ShadowTemplate {
    get {
        object obj = ResourceManager.GetObject("ShadowTemplate", resourceCulture);
        return ((System.Drawing.Bitmap)(obj));
    }
}

读取资源的代码也会有几个地方报错,比如,Bootstrap.cs中的Announce方法,由于源码使用的命名空间不一样,无法读取到方法,这里改为你项目的命名空间就好了

下面的NanUI077_SourceCode为我的命名空间

Log(NanUI077_SourceCode.Properties.Resources.nanui.White().OnDarkRed());

接下来将源码中的Resources文件夹拖拽到你的项目中,这些资源都用来显示浏览器的控制台。

打开Resources.resx,点击添加资源,将Resources文件夹所有文件选中添加,就如下图所示。

另外,将允许不安全代码勾选上,否则源码中的部分代码会报错。

如果你的源码正常运行,成功显示页面和控制台,js调用c# ,和c#调用js都正常,说明各方面搭建成功,可以开始下面的步骤。

我项目结构如下图,部分文件夹是我自己加的

打开ResourceHandlerRegister.cs ,这个脚本没有可以自己新建,这里我是导入了官方的嵌入式资源源码,所以已经有这个脚本了,这些源码可以搜索作者的github可以自行下载。

using System;

namespace NetDimension.NanUI
{
    public static class ResourceHandlerRegister
    {
        //读取嵌入式资源
        //参考:https://zhuanlan.zhihu.com/p/109022286
        public static Bootstrap UseAssembledResource(this Bootstrap _, ResourceHandlerScheme scheme, string domain, string basePath = null)
        {
            //GC.Collect();
            Bootstrap.RegisterCustomResourceHandler(() => new AssembledResource(scheme, domain, basePath));
            return _;
        }

        //REST资源处理器
        //参考:https://zhuanlan.zhihu.com/p/109023845
        public static Bootstrap UseRestfulService(this Bootstrap _, ResourceHandlerScheme scheme, string domain, Action<RestfulService.RestfulServiceProvider> provider = null)
        {
            //GC.Collect();
            Bootstrap.RegisterCustomResourceHandler(() =>
            {
                var resourceHandler = new RestfulServiceResource(scheme, domain);
                provider?.Invoke(RestfulService.RestfulServiceProvider.Create(resourceHandler));
                return resourceHandler;
            });
            return _;
        }

        //读取本地资源目录
        //参考:https://zhuanlan.zhihu.com/p/109023019
        public static Bootstrap FileResource(this Bootstrap _, ResourceHandlerScheme scheme, string domain, string filePath)// 如果您的资源处理器有其他参数,参数表因添加在末尾处)
        {
            //GC.Collect();
            Bootstrap.RegisterCustomResourceHandler(() => new CustomResourceFactory(scheme, domain, filePath));
            return _;
        }
    }
}

新建脚本 CustomResourceFactory.cs

using Chromium;
using NetDimension.NanUI.ResourceHandler;

namespace NetDimension.NanUI
{
    public class CustomResourceFactory : CustomResource
    {
        private string LocalDomain = string.Empty;

        public CustomResourceFactory(ResourceHandlerScheme scheme, string domain, string viewFolder)
            : base(scheme, domain)
        {
            string top = scheme == ResourceHandlerScheme.Http ? "http://" : "https://";
            LocalDomain = string.Format("{0}{1}", top, domain);
        }

        protected override ResourceHandlerBase GetResourceHandler(string schemeName, CfxBrowser browser, CfxFrame frame, CfxRequest request)
        {
            return new CustomResourceHandler(LocalDomain);
        }
    }
}

新建脚本 CustomResourceHandler.cs

using Chromium;
using NetDimension.NanUI.ResourceHandler;
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;

namespace NetDimension.NanUI
{
    public class CustomResourceHandler : ResourceHandlerBase
    {
        private string LocalDomain = string.Empty;

        protected override FormiumResponse GetResponse(FormiumRequest request)
        {
            FormiumResponse response = new FormiumResponse();
            if (request.Method != Method.GET)
            {
                Console.WriteLine("============[CustomResourceHandler]非Git请求");
                response.Status = (int)System.Net.HttpStatusCode.NotFound;
                return response;
            }

            string physicalFilePath = string.Empty;
            if (ReadFile.Instance.FilePathList.Count > 0)
            {
                int leng = request.RequestUrl.Length;
                int start = LocalDomain.Length + 1;
                string indexPath = request.RequestUrl.Substring(start, leng - start);

                for (int i = 0; i < ReadFile.Instance.FilePathList.Count; i++)
                {
                    if (ReadFile.Instance.FileNameList[i].Equals(indexPath))
                    {
                        physicalFilePath = ReadFile.Instance.FilePathList[i];
                        break;
                    }
                }
            }
            else
            {
                MessageBox.Show("[CustomResourceHandler] ReadFile 中资源列表 FilePathList 为空");
                response.Status = (int)System.Net.HttpStatusCode.NotFound;
                return response;
            }

            if (string.IsNullOrEmpty(physicalFilePath))
            {
                MessageBox.Show("[CustomResourceHandler] physicalFilePath 路径为空");
                response.Status = (int)System.Net.HttpStatusCode.NotFound;
                return response;
            }

            response.ContentStream = File.OpenRead(physicalFilePath);
            response.MimeType = CfxRuntime.GetMimeType(Path.GetExtension(physicalFilePath).Trim('.')) ?? "text/plain";
            return response;
        }

        public CustomResourceHandler(string localDomain)
        {
            LocalDomain = localDomain;
        }
    }


    public class ReadFile
    {
        private static ReadFile _instance = null;
        public static ReadFile Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new ReadFile();
                }
                return _instance;
            }
        }

        private List<string> _FilePathList = new List<string>();
        public List<string> FilePathList { get => _FilePathList; }

        //web前端代码在不同的文件夹可能出现同名文件,所以这里并没有使用字典这样的数据结构
        private List<string> _FileNameList = new List<string>();
        public List<string> FileNameList { get => _FileNameList; }


        private string ViewFullPath = string.Empty;

        public void Init(string dir)
        {
            if (_FilePathList.Count <= 0)
            {
                ViewFullPath = System.IO.Path.Combine(Application.StartupPath, dir);
                GetDirectoryFileList(ViewFullPath);
            }
        }

        private void GetDirectoryFileList(string path)
        {
            DirectoryInfo directory = new DirectoryInfo(path);
            FileSystemInfo[] filesArray = directory.GetFileSystemInfos();
            foreach (var item in filesArray)
            {
                if (item.Attributes == FileAttributes.Directory)
                {
                    GetDirectoryFileList(item.FullName);
                }
                else
                {
                    _FilePathList.Add(item.FullName);

                    int leng = item.FullName.Length;
                    int start = ViewFullPath.Length + 1;
                    string newPath = item.FullName.Substring(start, leng - start);
                    if (newPath.Contains(@"\")) newPath = newPath.Replace(@"\", "/");
                    _FileNameList.Add(newPath);
                }
            }
        }

        private ReadFile()
        {

        }
    }
}

调用,Program.cs

using NetDimension.NanUI;
using System;
using System.Windows.Forms;

namespace NanUI077_SourceCode
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            string View = "View";
            //读取web前端文件夹所有的资源
            ReadFile.Instance.Init(View);

            Bootstrap
            .Initialize()

            //读取本地资源
            .FileResource(ResourceHandlerScheme.Http, "www.app.local", View)

            .WithChromiumCommandLineArguments((procesName, cmd) =>
            {
                // 在此处处理CEF的命令行参数
            })
            .WithChromiumSettings(settings =>
            {
                // 在此处处理CEF的设置
            })
            .WhenLibCefNotFound(args =>
            {
                // 如果NanUI启动器没有检测到正确的CEF以及ChromiumFX运行环境,将执行此处理过程。
                MessageBox.Show("没有检测到Chromium Embedded运行环境,请确认libcef环境配置正确。", "libcef.dll is not found", MessageBoxButtons.OK, MessageBoxIcon.Error);
            })
            .Run(() =>
            {
                return new MainIndex();
            });
        }
    }
}

在这里还可以提升一下读取的速度,在ReadFile类中加入下面方法,每次打开网页的时候,就不用老是重复去调用IO去读取本地资源了,我测试过,整体流畅度确实提升一些,但整体读取速度不如NanUI0.88版本。

private Dictionary<string, FileStream> StreamDic = new Dictionary<string, FileStream>();

/// <summary>
/// 读取文件的FileStream
/// </summary>
/// <param name="areaPath">区域路径</param>
/// <param name="fullPath">完整路径</param>
/// <returns></returns>
public FileStream GetFileStream(string areaPath,string fullPath)
{
    if (StreamDic.ContainsKey(areaPath))
    {
        return StreamDic[areaPath];
    }
    else
    {
        //清除资源内存在 ResourceHandlerBase.cs 中的 OnRead 方法中
        //我将 formiumResponse.Dispose(); 这句注释了,否则读取会报错
        FileStream fileStream = File.OpenRead(fullPath);
        StreamDic.Add(areaPath, fileStream);
        return fileStream;
    }          
}

如果光这么写会报错,看代码中的注释,请将ResourceHandlerBase.cs 中 formiumResponse.Dispose()  这句代码注释

MainIndex.cs 脚本看我其他帖子,已经写了很多遍了,这里不贴代码了。

fx文件夹是cef的资源文件夹,这个如果没有,去你其他的NanUI0.77项目中拷贝过来放到Debug文件夹,或者安装NetDimension.NanUI.Runtime插件,版本选择0.77版。

安装完成后,在运行的时候,会自动生成cef文件。

在你的项目.exe文件同级目录下,加入一个View文件夹,将web前端代码放进去。

view文件夹

运行:

结束

如果这个帖子对你有用,欢迎 关注 + 点赞 + 留言,谢谢

end

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

熊思宇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值