您现在的位置: 365建站网 > 365学习 > C#/vb.net在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke错误的解决办法

C#/vb.net在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke错误的解决办法

文章来源:365jz.com     点击数:90    更新时间:2020-06-29 15:47   参与评论

C#/vb.net在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke错误的解决办法

情况:在C#开发的过程中多线程委托是经常用的,今天在测试以前写的软件的时候发现有个问题,报 在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。 这样的错误。

最近在所项目时,在耗时线程中,需要实时刷新界面进度,每次第一次都能成功显示进度,但是关闭窗口后,再次打开程序执行,则刷新失败,报错:在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。

试过多种方案无果!困扰许久!

问题的根本在于窗口没有完全释放!

今天偶尔发现,窗口在创建时会添加事件,当我们关闭程序且没有注销事件!我在窗口关闭时注销事件后,再次打开成功打开。问题解决!

 private void button5_Click(object sender, EventArgs e)
        {
            if (Form_ROI == null)
            {
                Form_ROI = new ROI(this);
                Form_ROI.StartPosition = FormStartPosition.CenterParent;
                this.TransfEvent += Form_ROI.frm_TransfEvent; //问题在这,调用窗体的时候注册了事件
                Form_ROI.Show();
                //Form_ROI.ShowDialog();
            }
        }



解决方法:关闭窗体的时候,注销事件


        private void ROI_FormClosing(object sender, FormClosingEventArgs e)
        {
            fm1.Form_ROI = null;
            fm1.TransfEvent -= this.frm_TransfEvent; //解决方法,注销掉事件
        }


另外解决方法:加上 if (this.IsHandleCreated)


1、首先分析问题,

句柄:是对象的引用名,存于栈区(可以理解为对象的指针),对象是存于堆区,通过操控栈区的引用名来操控对象。

控件上调用 Invoke 或 BeginInvoke的作用:由于C#是是强制类型安全的,当调用方线程与控件的线程(一般位于主线程)不在同一个线程,则调用方需要使用Invoke 或 BeginInvoke方法来间接委托的使用主线程的控件。


报错显示“在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke”

说明在当前控件的容器窗口并关闭了,应该是使用鼠标关掉了一个子窗口,不存在了(栈中保存的该窗体引用名被清除), 但是该程序包含多个窗口,关掉了一个窗口,程序还是在运行,但是在程序中的一个线程还想使用关掉的窗体上的控件,窗体关闭了,其包含的控件对象也消失了,因此报错。很可能是窗体关闭了,但是其线程还未执行完成消失。


2、这显然是线程不知道该控件已经消失了,还继续使用它造成的错误,因此我们在程序中添加 **if (this.IsHandleCreated)**判断窗体或控件的句柄是否还存在,之后才使用控件。


在调用下一个委托的时候。先判断下 在控件上面或者窗体上 IsHandleCreated ,如下:


if (this.IsHandleCreated)
{
    Methinvoker meth = new Methinvoker(MessSeInfo);
   this.BeginInvoke(meth);
}


1、如何获得一个窗口的句柄?

    例如获取窗口PictureBox控件(其他控件也可以)的句柄,

IntPtr handle = pictureBox.Handle;

2、注意:窗口创建和窗口创建完毕即有句柄完全是两回事!!!

    窗口创建时,窗口并没有创建句柄,只有Application.Run(form)或者form.Show()之后才有句柄,即窗口只有显示或者启动消息循环后才有句柄!如果创建form之后Form. form. = new Form(),主线程中调用form.Handle,如果句柄尚未创建,引用该属性将强制创建句柄,对系统内的逻辑将产生致命的影响。

    3、如何判断一个窗口的句柄创建完毕?

    利用IsHandleCreated 属性:此属性指示控件是否有与他关联的句柄,如果已经为控件分配了句柄,则为 true;否则为 false。

 4、一些属性:

    (1)、CreateControl :强制创建控件,包括句柄和任何子控件

    (2)、CreateHandle :为该控件创建句柄,

     通常,不应该直接调用 CreateHandle 方法。首选的方法是调用CreateControl方法,此方法在创建控件时强制为该控件及其子控件创建一个句柄。给继承者的说明 在派生类中重写 CreateHandle 时,请确保调用了基类的 CreateHandle 方法,以便确保已创建该句柄。

    (3)、DestroyHandle :毁坏与该控件关联的句柄

    (4)、FromChildHandle :检索包含指定句柄的控件

    (5)、FromHandle :返回当前与指定句柄关联的控件

    (6)、Handle :获取控件绑定到的窗口句柄,Handle 属性的值是 Windows HWND。如果句柄尚未创建,引用该属性将强制创建句柄。

    (7)、IsHandleCreated :指示控件是否有与他关联的句柄,如果已经为控件分配了句柄,则为 true;否则为 false。

    (8)、RecreateHandle :强制为控件重新创制句柄

    (9)、RecreatingHandle :指示当前是否在重创句柄

 5.注意:

    句柄是随机量,两次运行一般都会得到两次不同的结果


如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛


发表评论 (90人查看0条评论)
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
用户名: 验证码: 点击我更换图片
最新评论
------分隔线----------------------------