今天在实验Lua+WPF的时候碰到一个问题:
我在主线程中写的LUA虚拟机的 dofile,但当我要令LUA脚本执行阻塞的时候,同时也会阻塞UI线程。
于是我把对LUA的接口挪到另一个单独的后台线程中,专门负责与LUA脚本的交互。
编译一切正常,运行时THROW了异常,说不能在非创建UI元素的线程中改变UI元素属性。。
查了一下,C#就是这种机制,因为其GUI系统底层是内部单线程机制,所以为了避免各种乱七八糟的错误,直接禁用了跨线程的GUI元素操作。
查了一下,用了个Dispatcher的叫 “BeginInvoke” 的方法解决本问题。
其思想也就是异步调用,不过我估计是从GUI元素的dispatcher上分出时间片来启动线程。(没有深研究,不过总算搞定了这个问题)
主要代码如下,被注掉的部分是原来行不通的方法。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; using LuaInterface; namespace CodersLife { /// <summary> /// 工具类 /// </summary> class Super { /// <summary> /// 加载图片 /// </summary> /// <param name="address">图片地址</param> /// <returns>图片</returns> static public BitmapSource GetImage(string address) { return new BitmapImage(new Uri(AppDomain.CurrentDomain.BaseDirectory + string.Format("/Resource/Image/{0}", address), UriKind.Relative)); } } /// <summary> /// LuaAPI类 /// </summary> class LuaAPI { public Lua lua = new Lua();//初始化lua虚拟机 //public Thread luaThread; public Window1 MainWindow { get; set; } public void Start() { try { //绑定lua函数 lua.RegisterFunction("BackImage", this, this.GetType().GetMethod("BackImage")); lua.RegisterFunction("Music", this, this.GetType().GetMethod("Music")); lua.RegisterFunction("Debug", this, this.GetType().GetMethod("Debug")); lua.RegisterFunction("BindRolePic", this, this.GetType().GetMethod("BindRolePic")); lua.RegisterFunction("Dialog", this, this.GetType().GetMethod("Dialog")); //启动lua脚本 lua.DoFile("Script/Test.lua"); } catch (System.Exception e) { MessageBox.Show(e.ToString()); } } //切换游戏背景图片 public void BackImage(string image) { Brush brushInstance = new ImageBrush { ImageSource = Super.GetImage(image) }; MainWindow.Carrier.Background = brushInstance; } //切换音乐 public void Music(string music) { try { MainWindow.BackMusic.Stop(); MainWindow.BackMusic.Source = new Uri(AppDomain.CurrentDomain.BaseDirectory + string.Format("/Resource/Music/{0}", music), UriKind.Relative); MainWindow.BackMusic.Play(); } catch (Exception e) { MessageBox.Show(e.ToString()); } } private Dictionary<string, BitmapSource> _rolePic = new Dictionary<string, BitmapSource>(); //绑定角色图片 public void BindRolePic(string name, string pic) { _rolePic.Add(name, Super.GetImage(pic)); } //显示角色对话 public void Dialog(string name, string dialog) { BitmapSource Pic = _rolePic[name]; MainWindow.DialogInfo.Content = dialog; MainWindow.RoleName.Content = name; Brush brushInstance = new ImageBrush { ImageSource = Pic }; MainWindow.RoleHeadPic.Background = brushInstance; } //debug public void Debug(string info) { MessageBox.Show("debug info:" + info); } } /// <summary> /// Window1.xaml 的交互逻辑 /// </summary> public partial class Window1 : Window { LuaAPI luaApi = new LuaAPI(); public delegate void LuaThreadDelegate(); public Window1() { InitializeComponent(); InitLua(); } //初始化lua public void InitLua() { //luaApi.luaThread = new Thread(new ThreadStart(luaApi.Start)); luaApi.MainWindow = this; //luaApi.luaThread.Start(); Dispatcher.BeginInvoke(DispatcherPriority.Normal, new LuaThreadDelegate(luaApi.Start)); } //循环播放音乐 public void ReplayMusic(object sender, EventArgs e) { BackMusic.Stop(); BackMusic.Play(); } } }