`
rcfalcon
  • 浏览: 227954 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

WPF跨线程操作GUI控件

    博客分类:
  • .NET
阅读更多

今天在实验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#跨线程调用控件的四种方式

    在C#编程中,由于GUI(图形用户界面)控件是由主线程管理的,因此在其他线程中直接操作这些控件会引发"Cross-thread operation not valid"的异常。为了解决这个问题,开发者需要使用特定的方法来跨线程安全地调用...

    C#跨线程访问控件的实例

    然而,由于Windows Forms或WPF等GUI框架的线程安全特性,直接在非UI线程(后台线程)中修改UI控件的状态(如文本、颜色等)会导致“Cross-threading”错误,即跨线程访问异常。本文将深入探讨如何在C#中正确处理跨...

    Win32中创建并承载WPF控件并与WPF控件通信

    6. **线程同步**:由于Win32和WPF可能在不同的线程上运行,因此需要确保在跨线程操作时进行适当的同步。可以使用`DispatcherObject.Invoke`或`Dispatcher.BeginInvoke`方法确保操作在正确的线程上执行。 7. **资源...

    双色球查询字典子线程查询以及跨线程访问控件

    不过,在WPF或Windows Forms等GUI应用中,由于控件不是线程安全的,直接在非UI线程上修改控件状态会导致异常。这就是“跨线程访问控件”所要解决的问题。 为了在子线程中更新UI,我们需要使用“委托”和“事件”。...

    C#线程访问窗口控件问题

    在Windows Forms或WPF应用程序中,由于GUI(图形用户界面)组件是由UI线程(也称为消息泵线程)管理的,因此非UI线程直接操作这些控件会引发`System.InvalidOperationException`,通常提示“控件必须在创建它的线程...

    跨线程访问界面.7z

    然而,由于GUI控件是线程安全的,它们只能由创建它们的UI线程(主线程)进行修改。这就引出了一个关键问题:如何在后台线程上执行耗时操作并更新界面?本篇将详细讨论四种处理跨线程访问界面的方法,包括BeginInvoke...

    WPF开发教程

    调度程序处理跨线程调用,管理多个按优先级排序的队列,用于处理各类消息,如输入通知、布局更新或用户命令。在WPF中,线程关联的概念尤为重要,它指的是组件使用执行线程的标识来存储状态,通常通过线程本地存储...

    C#时钟控件

    7. **多线程考虑**:如果使用`System.Timers.Timer`,需要注意跨线程操作控件的安全性,可能需要使用`Control.Invoke`或`Control.BeginInvoke`方法。 8. **扩展性**:为了提高可复用性和灵活性,可以考虑将时钟控件...

    QQ登录界面的状态控件

    5. **跨平台兼容性**:如果目标是开发跨平台的应用,需要考虑控件在不同操作系统上的兼容性和表现。 6. **API调用**:如果控件需要与QQ服务进行交互,可能需要调用QQ提供的API接口来获取或设置用户状态。 7. **...

    第14章 创建图形用户界面GUI.ppt4.zip.zip

    4. **GUI编程框架**:常见的GUI库有Java的Swing和JavaFX,Python的Tkinter、wxPython、PyQt,C#的Windows Forms和WPF,以及跨平台的Qt等。这些框架提供了创建GUI应用的工具和API。 5. **事件驱动编程**:GUI编程...

    如何使用进度条控件?

    在软件开发中,进度条控件是一个非常实用的可视化组件,它能够向用户展示某个任务或操作的执行进度,提供用户界面的反馈,增加用户体验。本文将深入探讨如何在不同的编程环境中使用进度条控件,以帮助开发者更好地...

    drawRegionByThread_画图_多线程_

    这被称为跨线程操作,需要使用如`Control.Invoke`或`Control.BeginInvoke`方法来安全地更新UI。 3. **C# 多线程绘制**: - 要在多线程环境中绘制,通常会创建一个后台线程,负责计算和准备绘图数据,然后通过调用...

    Professional Windows GUI Programming Using C#

    C#作为.NET框架的一部分,正是在这种背景下逐渐成为开发Windows GUI应用的首选语言,因为它支持丰富的UI控件,易于集成Web服务,并且提供了强大的跨平台能力(如.NET Core和WPF)。 在C#中,Windows GUI编程通常...

    C#,Pos,Print打印控件

    6. **异步打印和错误处理**:为了提供良好的用户体验,打印操作应该尽可能地异步进行,避免阻塞UI线程。同时,必须处理可能出现的打印机错误,如纸张不足、打印机未连接等。 7. **多平台支持**:虽然C#主要应用于...

    不使用timer实现UI界面更新

    在编程领域,尤其是在Windows Forms或WPF这样的GUI...同时,这种方法也确保了线程安全,防止了跨线程访问UI控件可能导致的问题。在实际开发中,了解并熟练运用这些技巧对于构建健壮、高效的多线程应用程序至关重要。

    商业编程-源码-编辑控件源代码 dashline.zip

    编辑控件通常由程序员使用各种编程语言和库来实现,例如C++、C#、Java、JavaScript等,并且可能涉及到GUI库,如Windows API、Qt、wxWidgets、WinForms、WPF、HTML5的富文本编辑器等。在这些库中,往往有内置的文本...

    案例一 GUI数据传递和多窗口编程.zip

    数据绑定是GUI框架(如WPF, Qt, JavaFX)中的常见特性,它允许窗口控件自动反映模型数据的变化。这样,当数据在后台改变时,界面会自动更新,反之亦然。 5. **设计模式**: - **单例模式**:确保数据共享类只有一...

    qt5dll(UI).7z

    然而,WPF本身并不包含跨平台的GUI功能,这使得开发者在需要跨平台能力时可能转向Qt这样的框架。 将Qt DLL集成到WPF应用中,可以实现WPF与Qt之间的互操作性。这通常通过使用P/Invoke(Platform Invoke)或.NET的C++...

    C# 仿sikuli

    在 C# 中,我们可以利用 WinForms 或 WPF 的自动化树形结构(AutomationElement)来查找和操作 GUI 控件。然而,对于非标准控件或跨应用程序的交互,可能需要图像识别技术作为补充。 4. 自动化操作: 一旦找到...

    C#线程系列讲座笔记整理

    在Windows Forms或WPF应用中,由于UI控件不是线程安全的,必须在创建它们的UI线程(主线程)中进行操作。BeginInvoke和EndInvoke方法也可用于在非UI线程中更新UI, BeginInvoke将操作委托给UI线程执行,确保了安全性...

Global site tag (gtag.js) - Google Analytics