How can I use Control.Invoke () to throw an exception that will not be ignored?

Motivation

I use Task in a Windows.Forms application, where I want to handle any exceptions thrown by Task using Task.ContinueWith() and Control.Invoke() to recover any exceptions in the main UI thread.

However, I could not get an exception if I used Control.Invoke() - but it works if I use Control.BeginInvoke() .

Does anyone know why it does not work with Control.Invoke() , and how to make it work?

Bypass

I am currently using Control.BeginInvoke() to use instead of Control.Invoke()

Playback Steps

ENVIRONMENT: Windows 7 x64, Visual Studio 2012, compiled for .Net 4 (but .Net 4.5 is installed as part of VS2012).

(1) Create a default Windows Forms application with form1 .

(2) Place the button in the form named button1 and add a handler for it called button1_Click() .

(3) button1_Click() as follows:

 private void button1_Click(object sender, EventArgs e) { Task.Factory.StartNew(() => { Thread.Sleep(1000); this.BeginInvoke(new Action(() => { throw new InvalidOperationException("TEST"); })); }); } 

(4) Run the program and press the button. After a second, the window with exceptions that you expect is displayed.

(5) Now change this.BeginInvoke to this.Invoke .

(6) Run the program again and press the button. Now the exception is silently ignored!

Both Invoke() and BeginInvoke() are executed in the user interface thread for the specified Control , so I cannot understand why in one case the exception is ignored, and in the other it is not ignored ...

I suppose this should be due to the fact that Control.Invoke() will never return if it throws an exception, but my brain hurts, trying to understand why this means that the exception is (apparently) completely ignored.

+1
source share
1 answer

This is by design Invoke () handles exceptions differently than BeginInvoke (). It will march the exception back and throw it again so that you know that the called method has failed. This may not work for BeginInvoke () since the thread is already moved, so it rises in the UI thread. The next problem is that the Task class swallows exceptions, so you will never see it.

You do it with difficulty. If you like the default exception dialog, just use it with creating an exception in general:

 this.BeginInvoke(new Action(() => { using (var dlg = new ThreadExceptionDialog(new InvalidOperationException("TEST"))) { dlg.ShowDialog(); Environment.Exit(1); } 
+3
source

Source: https://habr.com/ru/post/1211551/


All Articles