今天在实验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();
}
}
}
分享到:
相关推荐
在C#编程中,由于GUI(图形用户界面)控件是由主线程管理的,因此在其他线程中直接操作这些控件会引发"Cross-thread operation not valid"的异常。为了解决这个问题,开发者需要使用特定的方法来跨线程安全地调用...
然而,由于Windows Forms或WPF等GUI框架的线程安全特性,直接在非UI线程(后台线程)中修改UI控件的状态(如文本、颜色等)会导致“Cross-threading”错误,即跨线程访问异常。本文将深入探讨如何在C#中正确处理跨...
6. **线程同步**:由于Win32和WPF可能在不同的线程上运行,因此需要确保在跨线程操作时进行适当的同步。可以使用`DispatcherObject.Invoke`或`Dispatcher.BeginInvoke`方法确保操作在正确的线程上执行。 7. **资源...
不过,在WPF或Windows Forms等GUI应用中,由于控件不是线程安全的,直接在非UI线程上修改控件状态会导致异常。这就是“跨线程访问控件”所要解决的问题。 为了在子线程中更新UI,我们需要使用“委托”和“事件”。...
在Windows Forms或WPF应用程序中,由于GUI(图形用户界面)组件是由UI线程(也称为消息泵线程)管理的,因此非UI线程直接操作这些控件会引发`System.InvalidOperationException`,通常提示“控件必须在创建它的线程...
然而,由于GUI控件是线程安全的,它们只能由创建它们的UI线程(主线程)进行修改。这就引出了一个关键问题:如何在后台线程上执行耗时操作并更新界面?本篇将详细讨论四种处理跨线程访问界面的方法,包括BeginInvoke...
调度程序处理跨线程调用,管理多个按优先级排序的队列,用于处理各类消息,如输入通知、布局更新或用户命令。在WPF中,线程关联的概念尤为重要,它指的是组件使用执行线程的标识来存储状态,通常通过线程本地存储...
7. **多线程考虑**:如果使用`System.Timers.Timer`,需要注意跨线程操作控件的安全性,可能需要使用`Control.Invoke`或`Control.BeginInvoke`方法。 8. **扩展性**:为了提高可复用性和灵活性,可以考虑将时钟控件...
5. **跨平台兼容性**:如果目标是开发跨平台的应用,需要考虑控件在不同操作系统上的兼容性和表现。 6. **API调用**:如果控件需要与QQ服务进行交互,可能需要调用QQ提供的API接口来获取或设置用户状态。 7. **...
4. **GUI编程框架**:常见的GUI库有Java的Swing和JavaFX,Python的Tkinter、wxPython、PyQt,C#的Windows Forms和WPF,以及跨平台的Qt等。这些框架提供了创建GUI应用的工具和API。 5. **事件驱动编程**:GUI编程...
在软件开发中,进度条控件是一个非常实用的可视化组件,它能够向用户展示某个任务或操作的执行进度,提供用户界面的反馈,增加用户体验。本文将深入探讨如何在不同的编程环境中使用进度条控件,以帮助开发者更好地...
这被称为跨线程操作,需要使用如`Control.Invoke`或`Control.BeginInvoke`方法来安全地更新UI。 3. **C# 多线程绘制**: - 要在多线程环境中绘制,通常会创建一个后台线程,负责计算和准备绘图数据,然后通过调用...
C#作为.NET框架的一部分,正是在这种背景下逐渐成为开发Windows GUI应用的首选语言,因为它支持丰富的UI控件,易于集成Web服务,并且提供了强大的跨平台能力(如.NET Core和WPF)。 在C#中,Windows GUI编程通常...
6. **异步打印和错误处理**:为了提供良好的用户体验,打印操作应该尽可能地异步进行,避免阻塞UI线程。同时,必须处理可能出现的打印机错误,如纸张不足、打印机未连接等。 7. **多平台支持**:虽然C#主要应用于...
在编程领域,尤其是在Windows Forms或WPF这样的GUI...同时,这种方法也确保了线程安全,防止了跨线程访问UI控件可能导致的问题。在实际开发中,了解并熟练运用这些技巧对于构建健壮、高效的多线程应用程序至关重要。
编辑控件通常由程序员使用各种编程语言和库来实现,例如C++、C#、Java、JavaScript等,并且可能涉及到GUI库,如Windows API、Qt、wxWidgets、WinForms、WPF、HTML5的富文本编辑器等。在这些库中,往往有内置的文本...
数据绑定是GUI框架(如WPF, Qt, JavaFX)中的常见特性,它允许窗口控件自动反映模型数据的变化。这样,当数据在后台改变时,界面会自动更新,反之亦然。 5. **设计模式**: - **单例模式**:确保数据共享类只有一...
然而,WPF本身并不包含跨平台的GUI功能,这使得开发者在需要跨平台能力时可能转向Qt这样的框架。 将Qt DLL集成到WPF应用中,可以实现WPF与Qt之间的互操作性。这通常通过使用P/Invoke(Platform Invoke)或.NET的C++...
在 C# 中,我们可以利用 WinForms 或 WPF 的自动化树形结构(AutomationElement)来查找和操作 GUI 控件。然而,对于非标准控件或跨应用程序的交互,可能需要图像识别技术作为补充。 4. 自动化操作: 一旦找到...
在Windows Forms或WPF应用中,由于UI控件不是线程安全的,必须在创建它们的UI线程(主线程)中进行操作。BeginInvoke和EndInvoke方法也可用于在非UI线程中更新UI, BeginInvoke将操作委托给UI线程执行,确保了安全性...