您的当前位置:首页>全部文章>文章详情

【C#】C# NLua Winform 热更新

CrazyPanda发表于:2024-02-18 22:44:29浏览:359次TAG:


一、概述

NLua 是一个用于 .NET 平台的 Lua 脚本绑定库。它允许在 C# 代码中嵌入 Lua 脚本,并允许两者之间进行交互。NLua 的主要特点包括:

  1. 轻量级:NLua 是一个轻量级的库,易于集成到现有的 .NET 项目中。

  2. 动态类型:Lua 是动态类型的语言,这意味着变量的类型可以在运行时改变。

  3. 灵活的绑定:NLua 提供了灵活的绑定机制,使得 C# 和 Lua 之间的数据交互变得简单。

  4. 丰富的 API:NLua 提供了丰富的 API,以便在 Lua 脚本中调用 .NET 的类和方法。

  5. 调试支持:NLua 支持调试功能,方便开发者在 Lua 脚本中设置断点、单步执行等操作。

  6. 社区支持:NLua 有一个活跃的社区,为开发者提供了一个交流和寻求帮助的平台。

使用 NLua,你可以在 .NET 应用中轻松地嵌入 Lua 脚本,从而实现动态逻辑、配置管理、插件系统等功能。通过 NLua,你可以利用 Lua 的灵活性和易用性,同时保持 .NET 的强大功能和性能。

NLua 支持 UWP、Windows、Linux、Mac、iOS、Android 平台。


NLua 源码和示例 Github 地址

GitHub - NLua/NLua: Bridge between Lua and the .NET.


二、创建项目

创建一个 .NET Framework  Winform 项目,这里我用的版本是 4.8.1,取名叫 NLuaDemo,在 NuGet 中安装 NLua 包。

1.png

winform 界面设计如下:

1.png

为了先看看 NLua 到底有没有效果,先做一个小案例,让你先熟悉一下 NLua 框架,在后面的案例中,会有完整的热更新方式展示。

需求:用 Lua 脚本来改变 Winform 界面中的抽奖人数,数量随意。

1.添加一个类 PublicData ,这个类用来保存公共数据(在第三节的案例中,这个类将不再使用)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
public class PublicData
{
    public static NLuaDemo.Form1 Form1s { get; set; }
}

我将 From1 保存在这里,主要是为了方便后面 Lua 调用。


2.将 Form1.Designer.cs 中的控件设置为 public,以便让 Lua 能直接调用 winform 控件。

1.png


3.将 Program 类改为如下(适用当前的 demo,在第三节的案例中,不再使用这种写法)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace NLuaDemo
{
    internal static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            PublicData.Form1s = new Form1();
            Application.Run(PublicData.Form1s);
        }
    }
}


4.Form1 代码如下(第三节案例中,代码会不一样)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using NLua;
 
namespace NLuaDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private Lua Luas = new Lua();
        //lua 脚本的地址
        private string LuaPath;
 
        private void Form1_Load(object sender, EventArgs e)
        {
            Luas.State.Encoding = Encoding.UTF8;
            LuaPath = $"{Application.StartupPath}\\main.lua";
            LoadLua();
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Luas.Close();
        }
 
        //热重载
        private void Button_HotUpdate_Click(object sender, EventArgs e)
        {
            Luas.DoString("update()");
        }
 
        private void LoadLua()
        {
            if (File.Exists(LuaPath))
            {
                Luas.LoadCLRPackage();
                Luas.DoFile(LuaPath);
                Luas["form1s"] = PublicData.Form1s;
            }
        }
    }
}


5.在项目的 Debug 目录中,新建一个 main.lua 文件,加入下面代码

form1s = {};
 
function update()
    form1s.Label_RaffleNumber.Text = "抽奖人数:100" ;
end

完成了上面的工作,现在可以开始测试了

01174706_63da351a96fff24847.gif

可以看到,Lua 脚本确实改变了 winform 界面的数据。


这里为什么不把逻辑直接写在 main.lua 中呢?

form1s = {};
 
form1s.Label_RaffleNumber.Text = "抽奖人数:100" ;
 
function update()
    form1s.Label_RaffleNumber.Text = "抽奖人数:100" ;
end

因为运行后就会报错:

1.png

由于 Lua 脚本在运行后,会执行所有的代码,但是我们定义的 Lua 全局变量此时还没有赋值,直接运行当然报错了,于是我将热更新内容写入到 lua 脚本中的 update 方法中,等 C# 这边初始化完成后,调用 update 方法就不会有问题了。

另外还有一种方法,使用 LoadFile 方法,我试了一下,没有效果,可能是我用法不对

LuaFunction luaFunction = Luas.LoadFile("C:\\test.lua");

有兴趣的朋友可以去试试,有好的建议欢迎留言评论。


三、实现 Lua 热更新

在上面的案例中,我们是把 Form1 赋值给了 lua 脚本中的 form1s 这个变量(也可以叫表单),其实还可以这么写:

private void LoadLua()
{
    if (File.Exists(LuaPath))
    {
        Luas.LoadCLRPackage();
        Luas.DoFile(LuaPath);
        Luas["this"] = this;
    }
}

但是这种用法在 Lua 脚本用会有错误,在 Visual Studio Code 中搭建好 Lua 开发环境,就会看到提示:未定义的全局变量 “this”

1.png

这个不用管它,lua 脚本只要在 C# 项目中运行不报错就行了。


这里的写法改变后,上一个 demo 中代码也要改改了。

1.Program 类恢复默认的写法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace NLuaDemo
{
    internal static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //PublicData.Form1s = new Form1();
            //Application.Run(PublicData.Form1s);
            Application.Run(new Form1());
        }
    }
}

2.PublicData 类可以删掉,或者注释所有的代码,现在用不上了。


另一个,Lua 调用 C# 方法,要用英文的冒号去调用方法,而不是像 C# 一样用点去调用,这个在 Unity3d 中 XLua 等热更新框架是同样的用法,具体用法可以参考下面 main.lua 代码。

--import("System")
--import('System.Windows.Forms')
--import("System.Threading");
 
--form1s = {};
 
--奖品
prize = {"手机", "电脑", "耳机", "鼠标", "键盘", "充电宝"}
--抽奖人
participant = {"张三", "李四", "老王", "狗蛋", "铁剩"}
 
--热重载
function update()
    this:Print("抽奖人 长度是:" .. #participant)
    this.Label_RaffleNumber.Text = "抽奖人数:" .. #participant
    this.Label_PrizesNum.Text = "奖品数:" .. #prize
 
    --奖品下拉框
    this.ComboBox_Prize.Items:Clear()
    for i,item in ipairs(prize) do
        this.ComboBox_Prize.Items:Add(item)
    end
    this.ComboBox_Prize.SelectedIndex = 0
 
    --抽奖人下拉框
    this.ComboBox_LotteryGiver.Items:Clear();
    for i,item in ipairs(participant) do
        this.ComboBox_LotteryGiver.Items:Add(item);
    end   
    this.ComboBox_LotteryGiver.SelectedIndex = 0
end
 
--抽奖按钮
function raffle()
    --随机奖品
    local prizeIndex = math.random(1, #prize) 
    local prize = prize[prizeIndex] 
 
    --随机抽奖人
    local participantIndex = math.random(1, #participant) 
    local participant = participant[participantIndex] 
 
    local content = "抽奖人:"..participant..",获得奖品:"..prize
    this:Print(content) 
end

注意上面 lua 脚本中的 Label_RaffleNumber,Label_PrizesNum,ComboBox_Prize 等关键字,这都是 winform 的控件,如果你用的不是我的源码,winform 控件名和 lua 脚本中的也不一致,那么运行就会报错:

错误:

1.png

当前 demo 所有的控件名

1.png


winform 这个控制台不知道怎么回事,lua 中打印用的 print 方法打印出来全是乱码,但是 winform 控件使用 lua 脚本中的中文还是正常的。

1.png

后面我只能在 Form1 中添加一个 Print 方法,这样打印才是正常的。

Form1代码:

using NLua;
using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
 
namespace NLuaDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private Lua Luas = new Lua();
        //lua 脚本的地址
        private string LuaPath;
 
        private void Form1_Load(object sender, EventArgs e)
        {
            Luas.State.Encoding = Encoding.UTF8;
            LuaPath = $"{Application.StartupPath}\\main.lua";
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Luas.Close();
        }
 
        //热重载 点击事件
        private void Button_HotUpdate_Click(object sender, EventArgs e)
        {
            LoadLua();
            Luas.DoString("update()");
        }
 
        //抽奖 点击事件
        private void Button_Raffle_Click(object sender, EventArgs e)
        {
            Luas.DoString("raffle()");
        }
 
        //加载 lua 脚本
        private void LoadLua()
        {
            if (File.Exists(LuaPath))
            {
                Luas.LoadCLRPackage();
                Luas.DoFile(LuaPath);
                Luas["this"] = this;
            }
        }
 
        //lua 打印用的
        public void Print(string text)
        {
            Console.WriteLine(text);
        }
    }
}

运行后,点击 “热重载” 按钮,就会看到奖品和抽奖人都有那些内容,这些都是由 lua 进行赋值的。

1.png

点击 “抽奖” 按钮,就可以看到当前的中奖人和奖品

1.png

既然是热更新,那我在运行过程中改变代码可以么?当然可以!

我们把 lua 脚本中抽奖人和奖品表单删除一部分,改完后记得保存,如下:

--奖品prize = {"手机", "电脑", "耳机", "鼠标"}--抽奖人participant = {"张三", "李四", "老王"}

再次点击 “热重载” 按钮,这时界面就发生了一些变化

1.png

抽奖人和奖品都少了

1.png

NLua 其实还有很多其他的用法,这里就没一一展示了。

上面的代码就是当前项目所有的源码了,创作不易,如果你觉得我的帖子对你有所帮助,也可以通过下载源码的方式来支持我,在此谢谢了。

源码:点击下载


结束

如果这个帖子对你有所帮助,欢迎 关注 + 点赞 + 留言

end

原文链接C# NLua Winform 热更新_winform集成lua-CSDN博客

猜你喜欢

【C#】C# Winfrom Chart 图表控件 柱状图、折线图
目录一、参考二、柱状图1.新建项目2.修改图表样式3.绑定数据4.删除Series1图例1)使用属性窗体删除2)使用代码删除5.自定义X轴的刻度值1)使用List绑定2)使用LabelStyle.Format绑定6.自定义Y轴的刻度值7.X轴刻度值显示不全的解决方法8.修改X Y刻度值的字体样式9.X轴刻度值旋转90°10.禁用Y轴刻度线11.去掉Y轴刻度值12.改变柱子的宽度13.设置网格线的颜色14.设置网格线的线型三、折线图1.图表设置2.绑定数据结束效果:一、参考c# Chart设置样式
发表于:2024-02-02 浏览:425 TAG:
【C#】C# Winform 自定义进度条ProgressBar
效果:一、前言Winfrom各种老毛病真的不适合做大型项目,甚至中型项目都不适合,一些小功能都能把你折腾半死,比如,我想在界面上显示一个进度条,用来显示现在硬盘和内存已经使用了多少,使用了 ProgressBar 控件你看看效果:进度条中间一直有个白色光影在晃来晃去的,是不是想让别人感慨:“哇!好强的光芒,我的眼睛快睁不开了...”。而且背景颜色无法改变,这个动画也无法关掉,为了解决这两个问题,我找了很久,终于找到了下面的解决方法。二、自定义进度条于是我在网上找了一些资料,有到效果有,但不是特别
发表于:2024-02-01 浏览:338 TAG:
【C#】C# Winform SplitContainer组件创建侧边菜单
效果一,SplitContainer 基本操作新建一个 Winform 项目,在Form1中拖进一个 SplitContainer 组件默认的界面如下这时候,你会发现,左侧菜单栏的宽度也太宽了吧,按照以前的经验,你一定会用鼠标去拖拽,这时候你就会发现,鼠标根本拖不动,不信你可以试试这时候,我们按Esc键,鼠标再移动到边框的时候,鼠标图标就会变成一个 “+” 状的图标,这时候就可以拖拽了此时,左侧的Panel1内还没有任何组件,运行后的效果我们添加一个按钮到&nbsp;Panel1 试试运行后发现
发表于:2024-02-01 浏览:550 TAG:
【C#】C# Winform 多个程序之间的通信(非Scoket)
效果功能:打开窗体自动连接主程序,并自动添加到列表,可以向子程序群发消息可以向单个程序单独发送消息在退出程序后,添加的程序列表会自动移除一、概述参考:C# Winfrom程序之间通讯_c# sendmessege copydatastruct 返回多个值_熊思宇的博客-CSDN博客在之前我写过 winform 程序与程序之间的通信,但是这个版本有个问题,那就是只能由两个程序进行通信,同时打开多个程序的话,接收方收到的数据就会一模一样,这次发表这个教程,也就是要解决这个问题。归根结底,还是&amp;nbs
发表于:2024-02-03 浏览:306 TAG:
【C#】Winform NanUI 0.77版本 读取本地资源(扩展功能)
一、前言在NanUI官方的文档中,原本是有一个NanUI.FileResourceHandler的扩展包的,但现在官方已经无法下载了,现在只有0.88版本中有一个NanUI.LocalFileResource程序包,而0.77版本只剩下了一个读取嵌入式资源的程序包。关于NanUI:NanUI | .Net/.Net Core界面组件NanUI 0.7版正式发布 - 林选臣 - 博客园在扩展功能之前,请参考[资源处理器]-04 自定义资源处理器 - 知乎&nbsp;,我参考这个帖子进行扩展的,也不
发表于:2024-02-08 浏览:338 TAG:
【C#】C# 自动更新(基于FTP)
目录一、前言二、功能的实现1.本地黑名单2.读取配置文件3.读取 FTP 文件列表4.读取本地文件5.匹配更新6.版本的切换三、环境搭建四、常见问题2023.12.30 更新结束效果启动软件后,会自动读取所有的 FTP 服务器文件,然后读取本地需要更新的目录,进行匹配,将 FTP 服务器的文件同步到本地Winform 界面一、前言在去年,我写了一个 C# 版本的自动更新,这个是根据配置文件 + 网站文件等组成的框架,以实现本地文件的新增、替换和删除,虽然实现了自动更新的功能,但用起来过于复杂,代
发表于:2024-02-03 浏览:367 TAG:
【C#】C#实现Excel合并单元格数据导入数据集
目录功能需求Excel与DataSet的映射关系范例运行环境Excel DCOM 配置设计实现组件库引入方法设计返回值&nbsp;参数设计打开数据源并计算Sheets拆分合并的单元格创建DataTable将单元格数据写入DataTable总结功能需求将Excel里的worksheet表格导入到DataSet里,是项目应用里常用的一种操作。一般情况下,worksheet是一个标准的二维数组,如下图:我们可以效仿 MS SQL SERVER 的一些基本导入选项,如首行是否包含数据,要导入哪个Shee
发表于:2024-01-29 浏览:356 TAG:
【C#】Winform NanUI 0.77版本 读取嵌入式资源
引入NanUI框架这三个组件都要引入了,NetDimension.NanUI.AssemblyResourceHandler 是属于嵌入式资源部分,下载地址:由于作者已经废弃了这个版本,在VS2019中的 NuGet 程序包 中已经下载不了,我这里上传了,有需要的可以点击下面链接下载NanUI.AssemblyResourceHandler.0.7.4&nbsp;下载&nbsp;另外,NanUI.AssemblyResourceHandler 源码github地址:GitHub - maxjov
发表于:2024-02-06 浏览:380 TAG:
【C#】C# Winform 定时清理日志
一、前言在 Winform 开发中经常有这样的需求,在用户执行一些操作不正确时,需要将错误信息反馈给用户,比如:登录密码不正确,无法连接到服务器等,一般常见的用法有两个:1.弹框使用&nbsp;MessageBox.Show(&quot;密码错误&quot;); 这样的方式,弹框后,用户必须点击确定后才能执行下一步操作,给用户的体验并不是特别好。2.在界面中显示错误信息,定时清除如果是输入框,直接用&nbsp;ErrorProvider 控件就行了。如果只是做一些简单的提示信息,那么就要定时清除
发表于:2024-01-31 浏览:307 TAG:
【C#】Winform解决方案打包成.exe 安装版Windows桌面应用程序
踩了几天的坑,慢慢爬出来了。帮助一下新手友人吧,高手请绕路。IDE Version:Visual Studio 20191.安装Microsoft Visual Studio Installer Project(1)打开Visual Studio 2019,扩展-&gt;管理扩展(2)搜索install,下载图中的扩展即可(我已经安装了,所以没有下载按钮)按照操作安装即可2.打包(1)右键 解决方案-&gt;添加-&gt;新建项目(2)搜索setup-&gt;选择 Setup Project-&amp;
发表于:2024-01-28 浏览:481 TAG: