问题描述
在我的 WPF Window_Loaded事件处理程序我有这样的事情:
In my WPF Window_Loaded event handler I have something like this:
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
// load data from database
this.Dispatcher.Invoke((Action)delegate
{
// update UI with loaded data
});
});
我想知道的是,当用户关闭表单数据时会发生什么从数据库和this.Dispatcher.Invoke程序被运行加载之前?结果
会不会有一个的ObjectDisposedException抛出?或将调度忽略调用程序(如窗口配置)?
What I want to know is what happens when the user closes the form while data is being loaded from the database and before the this.Dispatcher.Invoke routine is ran?
Will there be an ObjectDisposedException thrown? Or will the Dispatcher ignore the Invoke routine (as the window is disposed)?
我试过我自己的一些基本的测试想出解决办法,但我的结果让迄今已没有什么不好的事情发生。没有抛出异常,应用程序不会崩溃。
I've tried to figure this out my self with some basic testing, but my results so far have been that nothing bad happens. No exceptions are thrown and the application doesn't crash.
然而,我有几个不好的经验之前,当我用线程池的essentialy同样的事情。在Window_Loaded事件处理我排队一个新用户工作项目进入线程池,而数据加载我按下Esc键(我有一个Window_KeyUp事件处理程序监听Esc键,如果按下了叫this.Close( ))和应用程序崩溃时,它试图更新UI(内Dispatcher.Invoke),因为窗口已经关闭。
And yet I have had a couple of bad experiences before, when I used the ThreadPool for essentialy the same thing. In the Window_Loaded event handler I queued a new user work item into the ThreadPool, while the data was being loaded I pressed the Esc key (I had a Window_KeyUp event handler listen for the Esc key and if it was pressed it called this.Close()) and the application crashed when it tried to update the UI (inside Dispatcher.Invoke), since the window was already closed.
由于任务库使用线程池的背后在幕后,恐怕除非我写的代码来保护我的应用程序,这可能再次发生......
Because the Task library uses the ThreadPool behind the scenes, I'm afraid that this might happen again unless I write code to protect my application...
让我们改变场景有点 - 会发生什么当用户关闭的形式,而UI在常规Dispatcher.Invoke正在更新?结果
就形式收盘推迟到Invoke方法返回?或者可能有些异常被抛出?
Let's change the scenario a bit - what happens when the user closes the form while the UI is being updated in the Dispatcher.Invoke routine?
Will the form closing be postponed until the Invoke method has returned? Or could some exception be thrown?
如果有例外可能被抛出,如何最好地处理他们?
这是我能拿出最好的,是有一个的布尔readyToClose = FALSE; 的电线了WINDOW_CLOSING事件处理程序,它检查的如果(! readyToClose)e.Cancel = TRUE; 的然后,我已经更新了我的用户界面后,我可以,如果用户试图太早关闭表单设置readyToClose = TRUE,因此,它会被取消
The best that I can come up with, is to have a bool readyToClose = false; Wire up a Window_Closing event handler which checks if (!readyToClose) e.Cancel = true; Then after I have updated my UI I can set readyToClose = true, thus if the user tries to close the form too soon, it will be canceled.
或者我应该改用尝试{...}赶上(的ObjectDisposedException){//什么都不做}?
Or should I instead use try { ... } catch (ObjectDisposedException) { // do nothing } ?
推荐答案
在Windows窗体调用调用
上的一些控制(如您的主要形式)确实会抛出(如用户关闭表单) 。一个简单的方法来避免它会被使用的WinForms 的SynchronizationContext
类。这工作,因为 WindowsFormsSynchronizationContext
保留自己的内部控制,在其上调用调用
/ 的BeginInvoke
命令。看到
In Windows Forms, calling Invoke
on some control (such as your main form) will indeed throw if that control is disposed (e.g. the user closed the form). A simple way to avoid it would be using the winforms SynchronizationContext
class. This works because the WindowsFormsSynchronizationContext
keeps an internal control of its own, on which it calls the Invoke
/BeginInvoke
commands. see Exploiting the BackGroundWorker for cross-thread invocation of GUI actions on Winforms controls ?
在WPF中,的SynchronizationContext
委托给调度员因此使用它们中的是一样的。然而,由于WPF调度员是不是一次性的控件(也可以,虽然关闭),你不必担心一个的ObjectDisposedException
。不过,我相信调用调用
如果调度程序已关闭(因为它会等待操作永远不会完成)可能会挂起你的应用程序 - 调用的BeginInvoke
而不是应采取照顾。话虽这么说,线程池线程(这是由默认任务调度程序中创建的,如上面的情况)是后台线程不会妨碍退出停止你的过程 - 即使它们挂在调度.Invoke
电话。
In WPF, the SynchronizationContext
delegates to the dispatcher so using either of them is the same. However, since the WPF dispatcher is not disposable as controls are (it can be shut down though), you don't have to worry about an ObjectDisposedException
. However, I believe calling Invoke
may hang your application if the dispatcher has been shut down (since it would wait for an operation that would never complete) - calling BeginInvoke
instead should take care of that. That being said, ThreadPool threads (which are the ones created by the default Task scheduler, as in your case above) are Background threads which would not stop your process from exiting - even if they are hung on a Dispatcher.Invoke
call.
在总之,在这两个Windows窗体和WPF,使用 SynchronizationContext.Post
(在WPF相当于 Dispatcher.BeginInvoke
)会照顾你谈论的一般问题的。
In short, in both Windows Forms and WPF, using SynchronizationContext.Post
(which in WPF is equivalent to Dispatcher.BeginInvoke
) will take care of the general problem you're talking about.
让我们改变场景一点 - 当用户关闭的形式,而UI在常规Dispatcher.Invoke正在更新
这是不可能发生的会发生什么 - 而 Dispatcher.Invoke
调用运行在UI线程繁忙,特别是它不能处理用户输入,如键盘或鼠标点击的用户将需要关闭形式。
Let's change the scenario a bit - what happens when the user closes the form while the UI is being updated in the Dispatcher.Invoke routine?That can't happen - while the Dispatcher.Invoke
invoke is running the UI thread is busy, in particular it can't process user input such as the keyboard or mouse click a user would need to close the form.
这篇关于任务运行时,会发生什么,它的窗口被关闭?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!