在打开表单之前使用Invoke时发生InvalidOperationException [英] InvalidOperationException when using Invoke before the form was opened

查看:71
本文介绍了在打开表单之前使用Invoke时发生InvalidOperationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例外是:

System.InvalidOperationException:调用或BeginInvoke不能为在控件上调用,直到创建了窗口句柄.

System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

首先,我将在我的应用中说明这些关系.有一个名为MainForm的表单和另一个名为AssetsForm的表单.MainForm正在MainForm的构造函数中创建AssetsForm的实例,但是还没有AssetsForm.Show().

First I'll explain the relations in my app. There's a form named MainForm and another form named AssetsForm. The MainForm is creating an instance of the AssetsForm in the MainForm's constrcutor but doesn't AssetsForm.Show() it yet.

有一个名为AssetsSource的类,该类实现IObservable,并将要显示的数据发送到实现IObserver的AssetsForm.当AssetsForm接收要显示的数据时,它将创建一个处理数据并更新TreeView的BackgroundWorker.

There is class named AssetsSource which implements the IObservable and sends data for display to the AssetsForm which implements the IObserver. When AssetsForm receives data to display, it creates a BackgroundWorker which handles the data and update a TreeView.

我实现了以下错误代码,以处理BackgroundWorker中的UI更新:

I've implemented the following wrong code to handle the UI updates from the BackgroundWorker:

    private void Invoke(Control control, Action action)
    {
        if (control.InvokeRequired)
        {
            control.BeginInvoke(action);
        }
        else
        {
            control.Invoke(action);
        }
    }

这是错误的,因为我应该编写Action()而不是Invoke(action);但是我稍后会参考.无论如何,从Invoke(action)代码行引发了InvalidOperationException.我可以推断InvokeRequired评估为FALSE,尽管我是从BackgroundWorker更新TreeView的!!

It's wrong because instead of Invoke(action) I should have written action(); But I will refer to this later. Anyway, an InvalidOperationException was thrown from the Invoke(action) line of code. I can infer that the InvokeRequired evaluated to FALSE, although I update the TreeView from a BackgroundWorker !!

在MSDN中,它是有关Control.Invoke的内容:

In MSDN it is written about Control.Invoke:

Invoke方法搜索控件的父链,直到它查找具有窗口句柄的控件或窗体(如果当前控件的基础窗口句柄尚不存在.如果不可以找到合适的句柄,Invoke方法将抛出一个

The Invoke method searches up the control's parent chain until it finds a control or form that has a window handle if the current control's underlying window handle does not exist yet. If no appropriate handle can be found, the Invoke method will throw an exception.

什么是父链,什么是窗口句柄?创建窗口句柄时?我想所有这些都与AssetsForm已关闭的事实有关.

What is the parent chain and what is the window handle ? When the window handle is created ? I guess all this had to do with the fact that the AssetsForm is closed.

当我删除该行并仅使用action()时;确实应该如此,该程序不会崩溃.

When I removed that line and uses only action(); as it should be, the program doesn't crash.

在AssetsSource将更新发送到AssetsForm之前打开 AssetsForm 时,通过调试,我可以看到InvokeRequired被评估为TRUE,并且TreeView更新本身的BeginInvoke.

When the AssetsForm is opened before the AssetsSource sends updates to AssetsForm, by debugging I can see that InvokeRequired is evaluated to TRUE and BeginInvoke of the TreeView updates itself.

总而言之,我不明白为什么关闭AssetsForm时,那么InvokeRequired为false,并且允许UI更新(TreeView)来自未创建TreeView的线程.

To sum everything up, I don't understand why when the AssetsForm is closed, then the InvokeRequired is false and the UI update (TreeView) is allowed to be from the thread that didn't create the TreeView.

推荐答案

只要不显示该窗口,Winforms就不需要坚持UI线程机制.因此, InvokeRequired 返回false.

As long as the window is not shown, Winforms doesn't need to stick on the UI-thread mechanismn. Therefore InvokeRequired returns false.

如果调用 Show(),则将打开窗口,并且所有UI活动都需要通过事件循环(因此也要通过UI线程)运行.

If you call Show() the window is opened and all UI activities need to be run through the event loop and therefore through the UI-thread.

背景:仅通过主线程处理UI活动的限制是由于只有一个(Windows)事件循环正在处理所有与UI相关的活动.为了确保所有活动都以正确的顺序运行,所有操作都需要通过一个线程(至少在winforms中)运行.只要未显示该表单,就不会触发任何事件,因此无需强制所有操作都在主线程中运行.

Background: The restriction to handle UI activities only through the main thread is due to the fact that only one (windows) event loop is handling all UI related activities. To ensure that all activities are running in the correct order, all actions need to be run through one thread (at least in winforms). As long as the form is not shown, no events are triggered and therefore there's no need to enforce that all actions are run through the main thread.

添加一些背景说明.

这篇关于在打开表单之前使用Invoke时发生InvalidOperationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆