Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finish decoupling UI from code conversion #11

Merged
merged 9 commits into from
Mar 15, 2020
Merged

Finish decoupling UI from code conversion #11

merged 9 commits into from
Mar 15, 2020

Conversation

jnm2
Copy link
Contributor

@jnm2 jnm2 commented Mar 14, 2020

DoEvents is typically considered harmful. You can see some fun things on this topic if you google it. It causes the message pump to handle messages from more than one point in the program. This can cause events to execute out of order and event handlers to reenter themselves. I've seen it produce bugs in my own code and in third-party UI libraries that were not expecting to be subjected to such cruel and unusual interrogation.

The DoEvents docs page has this warning in a large red paragraph:

❌ Caution

Calling this method causes the current thread to be suspended while all waiting window messages are processed. If a message causes an event to be triggered, then other areas of your application code may execute. This can cause your application to exhibit unexpected behaviors that are difficult to debug. If you perform operations or computations that take a long time, it is often preferable to perform those operations on a new thread. For more information about asynchronous programming, see Asynchronous Programming Model (APM).

Async/await and Task have long since replaced APM. These days the standard pattern for work that is inherently blocking is to do it on a non-UI thread, typically on a thread pool thread using Task.Run. It's pretty easy to send updates to the UI thread from the worker thread once you know what to use, such System.Progress and SynchronizationContext.Post.

Since I want to run this in an app that does not depend on Windows Forms, I removed Application.DoEvents and moved the work to the background thread. There was a nice seam between the UI code and the conversion code so that I was able to add a single Await Task.Run to do the move.

➡ I ran the program before and after this change on https://github.com/nunit/nunit/blob/master/src/NUnitFramework/framework/nunit.framework.csproj. I could not tell a difference in program behavior. If you find a difference, I'm interested to fix it.

Commits

  1. Remove Application.DoEvents and Windows Forms references from code converter

Marshal progress updates from any thread safely to the UI thread

  1. Use Using block to dispose variable even if an exception is thrown first

  2. Use System.Progress to allow progress to be safely reported from any thread

  3. TextProgressBar should no longer implement System.IProgress directly because this forces System.Progress to be used, enabling updates safely from any thread

  4. Use clearer name now that TextProgressBar does not implement System.IProgress

Marshal exception reporting from any thread safely to the UI thread

  1. Use SynchronizationContext.Post to allow exceptions to be reported safely from any thread

Move conversion work to a background thread

  1. Run conversion process on a non-UI thread

  2. ByRef not allowed in async methods, refactor

@jnm2 jnm2 changed the title Finish decoupling UI from code conversion [WIP] Finish decoupling UI from code conversion Mar 14, 2020
@jnm2 jnm2 changed the title [WIP] Finish decoupling UI from code conversion [🚧 WIP] Finish decoupling UI from code conversion Mar 14, 2020
@jnm2 jnm2 changed the title [🚧 WIP] Finish decoupling UI from code conversion Finish decoupling UI from code conversion Mar 14, 2020
@jnm2
Copy link
Contributor Author

jnm2 commented Mar 14, 2020

@paul1956 Ready for review.

@paul1956 paul1956 merged commit 3601991 into paul1956:master Mar 15, 2020
@jnm2 jnm2 deleted the decouple_UI branch March 15, 2020 15:31
@GrahamTheCoder
Copy link

This move of splitting the library from the UI again gives me hope that one day that we could find a way to bring the library part of the project back together with https://github.com/icsharpcode/CodeConverter/ in some form so all our users can benefit from all our changes.

I opened #48 with one very promising case where you could just integrate a fix via nuget with a single method call possibly, there may be other similar cases in the changelog. Hope it helps!

Do feel free to open issues or PRs with fixes you've done here that might be portable. I'm considering doing some cs->vb winforms-related improvements for icsharpcode/CodeConverter#170

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants