WPF跨线程操作GUI控件

本文介绍了一个使用Lua脚本与WPF界面交互时遇到的跨线程修改UI的问题,并通过Dispatcher.BeginInvoke方法成功解决了该问题,确保了主线程与Lua脚本交互时UI的正确更新。

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

今天在实验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(); } } }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值