Compact Framework / Threading - MessageBox displays other controls after selecting an option

I am working on an application that captures and installs a lot of updates from an external server and needs some help with streaming. The user follows this process:

  • Click button
  • The method checks for updates, the counter is returned.
  • If greater than 0, ask the user if they want to install using MessageBox.Show ().
  • If so, it goes through the loop and calls the BeginInvoke () method for the run () method for each update to run it in the background.
  • There are some events in my update class that are used to update the progress bar, etc.

Progress bar updates are great, but the MessageBox is not completely clear of the screen because the update cycle starts right after the user clicks β€œyes” (see screenshot below).

  • What should I do if the message box disappears right before the start of the update cycle?
  • Should I use Threads instead of BeginInvoke ()?
  • Should I do an initial update check in a separate thread and call MessageBox.Show () from this thread?

code

// Button clicked event handler code... DialogResult dlgRes = MessageBox.Show( string.Format("There are {0} updates available.\n\nInstall these now?", um2.Updates.Count), "Updates Available", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2 ); if (dlgRes == DialogResult.Yes) { ProcessAllUpdates(um2); } // Processes a bunch of items in a loop private void ProcessAllUpdates(UpdateManager2 um2) { for (int i = 0; i < um2.Updates.Count; i++) { Update2 update = um2.Updates[i]; ProcessSingleUpdate(update); int percentComplete = Utilities.CalculatePercentCompleted(i, um2.Updates.Count); UpdateOverallProgress(percentComplete); } } // Process a single update with IAsyncResult private void ProcessSingleUpdate(Update2 update) { update.Action.OnStart += Action_OnStart; update.Action.OnProgress += Action_OnProgress; update.Action.OnCompletion += Action_OnCompletion; //synchronous //update.Action.Run(); // async IAsyncResult ar = this.BeginInvoke((MethodInvoker)delegate() { update.Action.Run(); }); } 

Screenshot

Windows Mobile Bug

+4
source share
3 answers

Your user interface is not updated because all work is done in the user interface thread. Your challenge:

 this.BeginInvoke((MethodInvoker)delegate() {update.Action.Run(); }) 

says update.Action.Run () is called in the thread that created "this" (your form), which is the user interface thread.

 Application.DoEvents() 

will really give the user interface thread the ability to redraw the screen, but I will be tempted to create a new delegate and call BeginInvoke.

This will execute the update.Action.Run () function in a separate thread allocated from the thread pool. You can then continue to check IAsyncResult until the update is complete, requesting the update object to execute it after each check (because you cannot update the current progress bar / UI), and then call Application.DoEvents ().

You will also need to call EndInvoke (), otherwise you may lose resources

I will also be tempted to put a cancel button in the progress dialog and add a timeout, otherwise if the update gets stuck (or takes too long), then your application will be blocked forever.

+6
source

Have you tried to put

 Application.DoEvents() 

here

 if (dlgRes == DialogResult.Yes) { Application.DoEvents(); ProcessAllUpdates(um2); } 
+1
source

@John Sibly

You can avoid using EndInvoke when working with WinForms without any negative consequences.

The only registered exception to the rule that I know of is in Windows Forms, where you are officially allowed to call Control.BeginInvoke without worrying about calling Control.EndInvoke.

However, in all other cases when you are working with the Begin / End Async pattern, you should assume that it will leak, as you said.

+1
source

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


All Articles