My application executes slower when I move its window - c#

My question might seem silly to you, but I realized that moving my applications form makes the code inside it run slower. E.g. when I load a bitmap image and apply some image editing algorithms on it, it takes about 22 secs for the whole process to finish. But if I move the form during execution, it adds some 3-4 extra seconds to the elapsed time. I was able to spot the delay using a Stopwatch. So how can I get around this behaviour, if possible at all?

This is just an hypothesis that requires your investigation, as you didn't post any code and thus it is impossible to really know what is going on.
Most probably you move the boundaries of the image outside the screen. When you move in again, the windowing engine will do some draw calls on those rectangles to be redrawn. The same happens on resize when you enlarge but not when you shrink the window.
If this is the case, then you will not experience any extra draw calls as long as you don't cover/uncover areas of the image.
So this is not an answer but in your place I would override the Paint() method and log how many excess calls are made. Based on this, I'd search for a solution, such as suppress those calls like this:
public override void Paint()
{
if (algorithmRunning)
{
return; // suppress any further computations
}
base.Paint(); // do actual redraws
}
This code is just an example, you'll have to fix it according to the MSDN documentation.
What you should NOT do is just hook into the OnPaint() event, because then you'll still have the actual Paint() method called.

Related

Helix Viewport continues zooming while paused at a breakpoint

I am running a Helix viewport and am catching a mousewheeled event with previewmousewheel to run a method. When debugging some changes I made to my methods I found out that when I set a breakpoint (anywhere between the catching of the mousewheeledevent and the subsequent applying of the zoom in the viewport) the amount of zoom from one detent of the mousewheel will increase continuously in proportion to the amount of time the program has been paused (basically the amount of time elapsed from the mousewheeledevent and the applying of the delta to the viewport). This makes debugging my changes the way I normally do seem not possible, though of course I can work around this.
The real problem is that now I realize that the zoom is completely erratic in this way, because some operations take longer than others between the event and the setting of the viewport, depending on what I'm doing.
This seems like a completely haphazard thing to have going on when I'm trying to make changes to a camera and completely control the camera behavior based on details specific to my program.
Is there any way to disable this from happening or mitigate it almost entirely?
The following code is a snippet from my program that seems to be the main driver of the issue, but I'm not sure I can just remove this method of keeping time in the program, because we definitely need an asynchronous timekeeper as far as I know.
private async Task DoWorkAsyncInfiniteLoop()
{
while (true)
{
if (Run)
{
Time.timeElapsed += Time.runSpeed;
Time.simTime += Time.runSpeed;
updateAll();
}
// don't run again for at least 200 milliseconds
await Task.Delay(Time.interval);
}
}
perhaps there is some lines I can add that will basically allow me to apply the zoom to the viewport without waiting for the await Task.Delay(Time.interval) line to run?
I must admit I'm not too clear on how that code works, but I do know that it stops at the await Task.Delay line before finally i hit "step into" (F11) one more time and it somehow just applies the monstrous zoom that was not wanted, without my seeing any code after that being run.
Any workarounds?
Try to set IsInertiaEnabled = false on viewport

How to redraw quickly on a canvas. C# WINFORM

For my software, I am using a Timer from Systems.timer library, every time my timer ticks, it calls a method for repainting my screen. I do not want to clear the screen, then to repaint on it. I just want to paint the new areas on it directly.
At the beginning, I did this:
Constructor{
...
this.timer = new Timer
{
Interval = 10,
};
this.timer.Elapsed += OnPaint;
this.timer.start();
}
public void OnPaint(Object sender, EventArgs e)
{
This.Parent.OnPaintLoadingCircle();
This.Parent.OnPaintReadyToBePaintedAreas();
}
Then I noticed it was much faster for painting when the OnPaint method contains this:
public void OnPaint(Object sender, EventArgs e)
{
This.Parent.Invalidate();
}
So I have two questions:
QUESTION 1 :
Why is it faster???
Because when I call invalidate():
The UI thread clears the screen.
Then UI thread redraws the old areas
Then UI thread draws the loading circle
Then UI thread draws the new areas.
And when I call my two methods OnPaintLoadingCircle() and OnPaintReadyToBePaintedArea():
The timer thread draws the loading circle
Then the timer thread draws the new areas
QUESTION 2 :
I would like to know if it exists a way for asking a controller to draw it surface without clearing it. ( I tried this.Parent.Update(), this.Parent.Refresh(), both of them first clear the screen as well).
Thank you very much for helping me.
Why is it faster???
For the simplest of reasons: because when you call Invalidate() in the OnPaint() method, it forces re-painting of the window immediately, which is much more quickly than a timer could.
The timers in .NET are not suited for high-frequency operations. They only guarantee the time between intervals will be at least what you specify. The actual interval can and often is longer than what you specify, especially if you are using a very short interval (e.g. on the order of less than 10-20ms). This necessarily limits how often you can re-paint the window when using a timer, to a much greater degree than just re-painting the window as fast as you can.
I would like to know if it exists a way for asking a controller to draw it surface without clearing it.
Not easily, no. At the most basic level, you can override OnPaintBackground() and not call the base implementation. But this approach only works if you are prepared to redraw everything, because the system counts on you covering up stale pixels with the correct pixels when you draw.
In fact, a much more common approach is to use double-buffering. The most basic form is to just set the DoubleBuffered property in the control constructor. But you can also combine not clearing the window with maintaining your own offscreen Bitmap object into which you draw your content. Then when a Paint event happens, you just copy the Bitmap to the window.
A much more complicated approach involves hosting a Direct2D surface in your window. Not for the faint of heart, but should offer the best possible performance in a Winforms program.

"flickering" pictureboxes due to being drawn while being moved

I am creating a program where users are able to use a GUI to create configuration files that bind commands to certain keys for a different unrelated program. In this program, I have a checkbox that allows the user to chose to use the DVORAK layout or the QWERTY layout. I have PictureBox-es being used for the image of each key. When the user checks the checkbox for the DVORAK layout, the program rearranges these pictureboxes so that they are now in the DVORAK layout instead of the QWERTY format. When this happens, about 90% of the time a few of the keys are drawn before they have moved, leaving 1 frame where there are keys overlapping or missing keys, causing a sort of "flicker".
I was wondering if there is any way to wait until right after the form's draw call has finished and then rearrange the keys to give the maximum possible amount of time for them to rearrange. I would need to be able to know the time until the next draw call (or if there is a constant amount of time inbetween every draw call, the time since the last draw call would also work) wait that amount of time, and then rearrange the pictureboxes.
Thank you for any and all help!
I had a similar problem with TreeViews. And, like TreeViews, PictureBox doesn't have a DoubleBuffered property. So I made a new control, using TreeView as the base.
Here's a PictureBox version of that class:
public class PictureBoxNoFlicker : PictureBox {
public PictureBoxNoFlicker() {
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
}
This code replicates double-buffering. Simply use this control instead of the standard PictureBox.
Unfortunately, I can't reproduce your problem, so I am taking a bit of a punt and hoping this resolves your issue.

C# Load Bitmap into PictureBox - slow and blocks UI .. any alternatives?

I am loading 640x480 Bitmaps into a picture box one after the other. When I do that my UI gets blocked. For example, if I was typing something in a text box which is on the same form where my picture box is, I would not be able to see the key that pressed right away, because the bitmap loading makes the UI very slow ..
How would one handle that ? is there any way around it ?
Any sample code would be great.
Thanks
A Picturebox is actually a fairly 'heavy' control in what it provides; it may not be the appropriate thing to use here. You might consider a much simpler container control, or drawing on the surface of the form itself.
If you want to consider BackgroundWorker or any other threaded technique here, keep in mind that the drawing itself must happen on the UI thread; there's no way around that.
If the loading of the images from disk is the source of the latency, you might consider loading the images into an in-memory bitmap on another thread, then signaling somehow to indicate that a new item is ready to be drawn. You would then invalidate the drawing surface, and add the new item as appropriate.
Also; if you are doing any scaling to the images, doing this in the background thread would be appropriate - that way, the drawing code itself only needs to draw an unscaled rect; Using the GDI+ DrawUnscaled functionality to copy a bitmap to an area of the exact same size is actually quite fast.
To get into anything more specific, like actual code, I would want to see code for how you are doing it now. I'm not even sure you are 'drawing' the images in the first place, rather than simply setting Picture/Image properties.
Use background worker so the gui is not freezed (async invoke the image display).
http://www.dreamincode.net/forums/topic/112547-using-the-backgroundworker-in-c%23/
Your second request is a bit more tricky, I guess short answer would be not to rely on gdi+ if that's what you are doing be cause it's known to be slow. How exactly do you load the image into the imagebox?

Simultaneous updates across two display contexts in openGL

I have a C# .NET application with which I've created a custom image display control. Each image display represents its own display context and draws the image using glDrawPixels (Yes I know it would be better to use textures, I plan to in the futures but this app is already too far along and my time is limited).
I am now trying to have both images pan simultaneously. That is, when one image is moved down ten pixels, the second image moves down ten pixels. Like so:
imageOne.YPan -= 10;
imageTwo.YPan -= 10;
imageOne.Invalidate(); //This forces a redraw.
imageTwo.Invalidate(); //This forces a redraw.
Alright so here is the problem I am having. Only one of the images displays is redrawing. If I place a pause in between the two Invalidate calls and make the pause duration at least 110 milliseconds both will redraw, but not simultaneously. So it looks as if the second image is always trying to catch up to the first. Plus, a 110 millisecond pause slows down the motion too much.
I have tried placing the updating and invalidating of each image in its own thread but this did not help.
At the beginning of drawing I make the appropriate context is current, and at the end I am calling swapbuffers(). I tried adding a glFinish to the end of the draw function, but there was no change.
Could it be that its the graphics card that is the problem? I am stuck using an integrated gpu that only has openGL 1.4.
Hopefully, I have provided enough detail that the answer to my problem can be found.
Its difficult telling what's wrong with what you do since you give so little detail. Here are some pointers which may help.
- before doing something in a context, make sure you make it the current one. If you want to pan two contexts, make the first one current, pan it and then make the second one current and pan it. These is no real reason why this should not work.
- If it looks like there is a timing problem, adding glFinish() at strategic places may help weed the problem out
- As should always be done, on occasions call glError() and see that everything went well.
- I'm not sure how this is done in the framework you're talking about but you should make sure that both contexts get a swapBuffers() call for every frame.
Invalidate doesn't force an immediate redraw. It marks the window invalid, and when the message queue runs out of other messages, a paint message will be created and processed. But that won't happen until you finish processing the current message and return to the main message loop, and it may be delayed even more than that.
Generally OpenGL animation is an exception to the rule of doing all drawing inside Control.OnPaint (or in a handler for the Control.Paint event).

Categories