I have a program which needs to do two separate functions simultaneously.
The first is updating the picturebox with a new Bitmap, the second function is a simple function which is effectively instantaneous.
However, because of the delay in updating the picturebox, there is a noticeable delay between the two. The basic code is as follows:
this.pictureBox1.Image = bmp;
this.Invalidate();
OtherFunction();
I have disabled double buffering, and tried all kinds of .Update(), .Refresh(), Application.DoEvents(), but nothing seems to make it any faster.
From my research it seems that setting the Invalidate Flag just means that next time something comes round looking for invalidated forms, it will update it. Is there a way to trigger this manually?
I would rather not introduce a Thread.Sleep() line unless absolutely necessary
Have you seen this question? Maybe you haven't tried the exact magic sequence of calls that force the control to update.
Related
Some Background
I am writing an application that moves a multitude of windows on the screen which demands a real-time constraint. I normally set the window positions using the following format:
this.Left = position.x;
this.Top = position.y;
The Question
What I would like to know is if this is the fastest, or most efficient way to do this. Does setting the Left automatically fire off an event to refresh, or does it wait for an OnRender event?
Secondly, why isn't there a function to simply set the position altogether? Or is this even necessary? I am aware that the Windows API has SetWindowPos, but I would prefer to stay away from unmanaged code. Would using this function be faster?
I'm not sure if it's the most efficient but calling it multiple times may have performance issues. The reason for this is because the Left and Top dependency properties have a PropertyChangedCallback instance set to the OnPositioningChanged method. This method calls InvalidateArrange. From the link:
Frequent calls to InvalidateArrange or in particular to UpdateLayout
have significant performance consequences.
I know it's an obvious answer but the best way would be to benchmark both methods and see which one works for you. Regardless of whether you go the unmanaged route or stick with your current method, I imagine the same rendering calls will have to be made at some point (happy to be corrected on that).
I have a very fast loop which renders animation in a Bitmap buffer and adds filter to it (by using LockBits/UnlockBits to access to the raw data and Marshaling changes to it.) in an independent thread.
I wanted to figure out a way to display the render on the Form, real-time, so I created a PictureBox and linked its Image to the bitmap I created. Everytime immediately after the bitmap is unlocked, I refreshed the PictureBox (using delegate, to do cross-threading) so that the rendering is updated properly.
It's totally fine and works very fast, but one big problem came out as I tried dragging the form to the border of the screen, to see if any bug would appear, and oops, the app collapse..saying 'the bitmap is being locked' This happens when either there's other window moving above the PictureBox or the PictureBox is dragged partially out of the screen. I suspice it because PictureBox can refresh itself when redraw is neccessary, and it does when the bitmap is still being locked. So...any way to sovle this problem? Or anyother ways to render the my animation better?
One of possible solutions could be is create your custom MyPictureBox : PictureBox (say) class which override OnPaintBackground, like this:
protected override OnPaintBackground(...)
{
// nothing, an empty method
}
But I'm not very sure that this will work, you should to check this by yourself.
What I would do, personally, considering your comment:
I have a very fast loop which renders animation in a Bitmap buffer and
adds filter to it (by using LockBits/UnlockBits to access to the raw
data and Marshaling changes to it.) in an independent thread
just forget about PictureBox, cause I found it, personally, too generic and non suitable for high performance rendering. Just write a simple class that handles the drawing of specified bitmap on specified surface.
Imo, this is a best choice.
You can't do that.
Instead, you should copy the image (on the background thread) and put the copy in the PictureBox.
For better performance, you can swap between two images to avoid creating too many images.
I am currently working on a Windows.Forms application. It's basically a simple motion detection problem.
I have a button on a form, that when pressed launches a background worker that does the following :
Fetch an image from disk
Create a new bitmap, to be used as the buffer.
Perform Motion Detection
From the results of Motion Detection, update the buffer (using the buffer's drawing surface)
Fire the Progress Changed Event with an argument consisting of a clone of the buffer, basically (sender as BackgroundWorker).ReportProgress((Bitmap)buffer.Clone())
In the Progress Changed Event, I then draw the buffer to screen.
if (!PnlImage.IsDisposed)
PnlImage.CreateGraphics().DrawImageUnscaled(buffer, 0, 0);
I can't help wondering if this is the best way to draw the updated image on the screen. Can anyone suggest any improvements I can make?
Thanks.
EDIT :
I have since updated the program to use the .NET Framework 4, and we're no longer using a BackgroundWorker. Instead, we are now using the System.Threading.Tasks namespaces, and using Invoke to update the background image from within the task.
Thanks to all replies.
I believe the root of any problems you may be experiencing is the fact that any GUI updates must be done on the UI thread. You cannot safely update the UI from another thread. So, basically, you need to do something like the following (I'm just changing the background color as an example, but you can do whatever you like):
private void SomethingCalledFromBackgroundThread()
{
panel1.Invoke(new DoUpdatePanel(UpdatePanel), Color.Blue);
}
private delegate void DoUpdatePanel(Color aColor);
private void UpdatePanel(Color aColor)
{
panel1.BackColor = aColor;
}
============ Update =======>
#Ash you have mischaracterized my answer. I did not say to call Invoke from within ProgressChanged. #Jean keep in mind that ReportProgress/ProgressChanged is being run asynchronously--which is why you find yourself making a clone of your image. This would not be necessary if you use Invoke from within your background thread, rather than ReportProgress.
I'm not sure if this is strictly true but I'm sure you can't cross thread GUI/Control operations on a separate thread as it is handled by default on a dedicated GUI thread.
I tried to do something similar to this before and in the end i decided on an entirely different approach to it as setting a property to false was the worst way to get it to work.
The ProgressChanged and RunWorkerCompleted Events allow you to update the UI directly. It is only the DoWork event handler that you must not access the from. See MSDN:
You must be careful not to manipulate
any user-interface objects in your
DoWork event handler. Instead,
communicate to the user interface
through the ProgressChanged and
RunWorkerCompleted events.
This is one of the major benefits in using the BackgroundWorker over creating your own thread. So TheObjectGuy is not correct, you do not need to use BeginInvoke/Invoke in ProgressChanged.
As long as your image is not too large, cloning it should not cause any serious performance issues. Run some performance tests with bigger images if you have concerns.
Otherwise, to avoid tricky synchronization issues such as using lock, I think making a clone of the image is a good way to keep things simple.
Using the ProgressChanged event is fine. What is not fine is drawing directly to the screen. Your image will disappear when you minimize and restore the form. The workaround is simple:
PnlImage.BackgroundImage = buffer;
I need to build a Windows control that displays KPI indicators. Something similar to the one displayed at the following picture.
alt text http://www.novolocus.com/wp-content/uploads/2008/03/normal.JPG
There are also the following requirements:
List needs to refresh from a background thread every ~15 seconds
It needs to handle 100+ indicators
My initial idea was to use FlowLayoutPanel with a combination of a label and picturebox (for each row). I managed to create exactly the same thing but as list grows and refreshes itselft, UI becomes unresponsive and memory footprint is increasing.
I tried the same approach with GridView and some 3rd party components but every time the result was similar UI would eventually freeze completely because it could not handle that many items refreshing.
So, how would you approach this problem, what would you do create this control, which objects would you choose to build UI and how would you refresh it. (If there is a 3rd party control that looks good that might also work for me).
A layout like that should not lead to an increasing memory footprint, or a slowdown.
Your description sounds more like a resource leak in your control (not Disposing graphic objects). Make sure that you know that the IDisposable interface implies the need of using(){} for Brush, Graphics and Image objects.
A short sample:
using (Graphics g = Graphics.FromImage(picture))
using (Brush fill = new SolidBrush(Color.Yellow))
{
g.FillRectangle(fill, x0, y0, x1, y1);
}
I have a Windows form application written in C#. I update the title of the form frequently, but there's a substantial lag between the title changing and the title dislayed in the taskbar being updated.
What's a clean way to force an update / redraw of the task bar's entry for my program? Failing that, how can I force a redraw of the entire task bar?
Elaboration: It turns out that the delay in updating the taskbar is fixed at about 100ms, however this seems to be a delay based on when the Form.Text was last modified. If you modify the text faster then that - say, every 10ms, the taskbar is not updated until the Form.Text has been left unchanged for at least ~100ms.
OS: Vista 32.
Did you try to call Form.Refresh() after updating the title?
Edit:
If you are doing the title updates in a loop you might have to do something along the line of:
this.Invalidate();
this.Update();
Application.DoEvents();
A task bar update more than every 100ms is going to be too fast for the user to resolve anyway. Presumably you're showing some sort of progress or status indicator to the user?
If so, you're crippling the app needlessly doing so many UI updates. That processing time is better used getting the customer's job done.
I think you need to revisit the UI design aspects of what you're trying to do.
I just did a simple test. The changes are quite instantaneous. From the look of it, it's definitely less than 500ms. If you need to update the title at a higher rate, I won't really recommend it. Generally I've seen the fastest update rate of twice per second.
EDIT:
I tested using keypress event. When I hold down the key for a fast repeat, it won't update until I've release my key. Thus, same scenario as your setup.
Btw, why do you need to update every 10ms? Just keep in mind that Thread.Sleep(timeout) with timeout of less than 50ms is not accurate. Also, 10ms timeout will equal to 100Hz, unless you're using high end display, you'll have miss a few frame. Most general LCD have a refresh rate of 60Hz. And our eye can't differentiate anything faster than 25Hz. Thus 40ms delay is more than enough, if you want to animate. Generally I would recommend 15Hz (67ms) for simple animation. If just want to scroll some text, 2Hz is more than enough. Anything faster will make the user dizzy.
Are you using code similar to this in your form?:
private void Form1_Load(object sender, EventArgs e)
{
Timer t = new Timer();
t.Interval = 10;
t.Tick += new EventHandler(t_Tick);
t.Start();
}
int aa = 0;
void t_Tick(object sender, EventArgs e)
{
this.Text = aa++.ToString();
}
Works fine for me - no lag between form and taskbar at all.
Are you sure you aren't locking up the GUI thread and not calling Application.DoEvents on your loop?
I'm using the new Windows 7 beta, so it's a small chance that it's different behavior.