How to make windows form UI responsive? - winforms

This is a common problem for all developers, I am looking for the best solution to make windows forms UI responsive.
I have an animated GIF file to show progress of my calcuation on windows form. I took a picture box control and placed animated gif into that. now when my calcuation starts - the animaged gif freezes. I want the reverse, the animation should be visible when i am running the calculation.
Any to the point thoughts? A simple solution is to display a progress bar to the user while doing complex calculations behind the scene
My app is a single threaded application, and I want a simple solution, not looking for multi-threads, or background worker kind of technologies.
Any help?

Multiple threads would be my recommendation. A bit messy first time you try ;)
Simplest model: One thread for the GUI, and one thread for whatever work you need to do.
Check this link.

Application.doevents
You place it in the loop. It gives the UI the time to do its things.

Well, the only real way to do 2 things at once (like do calculations, and still keep responsive) is to use threads. If you won't want to explicitly use threads, then check to see if there are any asynchronous calls you can use to do it in the background. Aside from that, do a lot of Application.DoEvents calls wherever you do lots of work.

I'm going to have to site Jeff on this one:
Coding Horror: Is DoEvents Evil?

"simple solution to display a progress to the user while doing complex calculations behind the scene ?"
"not looking for multi-threads, or background worker kind of technologies."
Which of those wishes is more important to you? You'll have to choose one or the other.

Related

How should I implement non-event-based actions in WPF?

I come from a couple years' background in looped game programming. I'm very used to having a constant loop in my application which continually calls functions like Update and Draw, allowing me to perform actions like animations over time by incrementing values a bit each frame.
Now that I've got a job involving WPF, though, I find that I was too reliant on that system. Maybe I've got a limited feel for WPF, but it seems like everything is event-based. User clicks a button, you inform the code, the code manipulates values. The values change, code informs UI, UI updates layout. It works well for GUI-based application programming but I find that when I encounter situations which would be trivial in loop-based game programming I am stuck, unable to find a good way to implement simple behaviors.
At the risk of being too vague I'll provide my current problem as an example. After Windows 8 was unveiled I became very enamored with the idea of Semantic Zoom. After playing around with the Start Screen extensively I began working on a port of Semantic Zoom to WPF4.0 for Microsoft Surface (I work with the Surface at my job). I just want a trivial example of it which would allow me to use pinch gestures to navigate up and down in a stack of views.
After many hours spent trying to understand manipulation events (I won't go into that... bleh), I've finally got my view scaling based on a pinch gesture. If it scales past a certain point I jump back to the 'zoomed out' view. Pretty cool. But, the problem is, if the user doesn't complete the gesture and decides not to zoom out, I'm left with a smaller view. I want to animate the scale of the view to constantly 'rebound' from user pinching and restore to a scale of 1. I know if this were loop based I'd just Lerp toward 1 each frame. But since WPF is all based on events, I'm a little lost.
There's probably an answer to this specific problem using inertia or different manipulation events (and I'd be happy to hear it), but in addition I'd just like to know how I can re-orient my mindset to work more effectively in WPF. Is it just about knowing which events to subscribe to? Are there clever ways to use Animations to do what I want? Should I use threads to accomplish these kinds of tasks, or is that cheating (it seems unreliable, plus I'm shaky on threads in WPF)?
This issue is one of my biggest barriers to being effective in WPF, I think (well, this and not quite knowing MVVM yet, working on that). I'd like to see it torn down and be able to be effective in more than just loop-based games programming.
Although i'm pretty sure that most of what you want to do can be done in an event-based manner, you might want to take a look at the MSDN How to: Render on a Per Frame Interval Using CompositionTarget. Please also note the final section Per-Frame Animation: Bypass the Animation and Timing System in Property Animation Techniques Overview.

How to keep a winform responsive while a heavy painting is underway

My program draws heavily on a winform. During the drawing, the winform is not responding. How to make it responding to my mouse? I want to use another thread to draw to the winform, but I am afraid I am going to meet the infamous cross-threads-access-conrtrol error.
Here is a great MSDN article that might help you: Give Your .NET-based Application a Fast and Responsive UI with Multiple Thread
When I was facing similar problems, it helped me a great deal to understand what to do.
Also, you might want to have a look at Parallel Programming in .NET Framework 4. This series also includes a strategy with calculations that are spread over multiple synchronized threads, all with using out-of-the-box .NET collections. This is not as complicatesd as it may sound. Just give it a try. :-)
Also, if you have the chance to use the upcoming .NET enhancements, it would be worth to try Asynchronous Programming with Async and Await
If the problem is GDI+ painting you can do all of your drawing on a separate bitmap in a separate thread (instead of drawing directly to screen) - and when you're done: copy the whole bitmap onto the form.
You can use BackgroundWorker class to keep your winform responsive. MSDN.
The problem is when you are performing UI stuff. You have to come back into the UI thread to do so. All I could recommend, is drawing a bit, letting the UI thread process any events, draw again a bit.
Thats probably the best way round, but it isnt easy to do ... Far less easier than just running non UI jobs in another thread ...

running an openGL engine in WPF in a separate thread

I have an openGL rendering engine coded in unmanaged C++, and I want to embed this in a WPF application. After a little research, I managed to do it by using the handle of a windows forms panel in a windowsformshost, as explained here (2nd solution):
http://www.codeproject.com/Articles/127141/Unmanaged-C-OpenGL-Drawing-and-C-WinForms-WPF-inte/?display=Mobile
So far good. The problem is, I need the render to be real time, and when some UI operation takes too long (like populating a property grid), the render flickers.
Then I guess I need to do the rendering in a separate thread. I tried to use this approach:
http://blogs.msdn.com/b/dwayneneed/archive/2007/04/26/multithreaded-ui-hostvisual.aspx
But it does not work because it seems i cannot place a windowsformshost inside a HostVisual (http://social.msdn.microsoft.com/Forums/en-AU/wpf/thread/124cc95c-a9c6-4aca-a5fc-4f959ea715c3)
So, any idea how can I do this?
If you use double-buffering then it should never flicker. See the section "How to Avoid Flickering?" in the first article you linked to. You can also try inserting Application.DoEvents() calls inside code that takes a long time to execute. Just some suggestions as an alternative to the added complexity of using a threaded solution.
EDIT: just realized WPF does not support DoEvents(), but there are alternatives: http://nmarian.blogspot.com/2007/09/doevents-in-wpf.html

WPF - Navigation blocks application (poor performance)

I have a WPF application which generates MIDI notes (a sequencer).
Besides the UI thread, there is a timer thread which triggers notes. In general, the timing is ok, but I have the following problem: Whenever I do any navigation, the application seems to "block" (i.e. the timer "stumbles" and the output stops for a short time). This happens when I e.g. open a new window or perform a navigation on a navigation window.
This also happens when I navigate to a page which is already instantiated and has been shown before.
Does anyone have any ideas?
EDIT: I think the actual question is: Does anyone know of a way to make navigation faster?
I'm not sure, but wouldn't your eventhandler (_midiInternalClock_Tick) be executed in your UI thread?
So the MidiInternalClock might be executing in another thread, but the handling of the ticks wouldn't. Like I said, not sure about this.
You might want to separate the code that works with the Midi toolkit to a separate class and then construct the clock en handle it's events in a different thread.
If that doesn't help, I'm at a loss. I guess you would then best ask your question on the CodeProject page.

Is there a way to make .net winform tool tips behave less haphazerdly?

I find that the winform tool tips behave very erratically. They seem to randomly decide to do nothing, show up or disappear when I perform the same hovering/clicking/etc actions.
Is there some pattern that I'm missing? Do I just not understand the UI technique to bring up a tooltip? Is this a common problem? Do people actually expect tool tips to work this way?
Tooltips display automatically. That's a bit of a problem, the native Windows control has counter-measures in place to avoid displaying tips too often, potentially wearing out the user with info that has been shown frequently enough. Not exactly sure how that rate limiting is implemented, accumulated time is a factor (like 60 seconds), possibly also the number of times it was displayed.
The SDK docs do not document the implementation details. There is also no message available to forcibly reset the rate limiter. I do think that passing another control in the Show() method resets it.
All and all, it does mean that the ToolTip control is really only suitable to act as a traditional tool tip. It doesn't work well as a 'dynamic label'. which is your alternative, a Label control with BackColor = Info. Albeit it not quite the same because you cannot easily make it a top-level window.

Resources