Disposing Brushes - c#

I am having a few memory problems with a long running application; I have been inspecting the paint methods to insure that brushes are properly disposed. In the case where the Brush is created in the argument to the function, will the brush be disposed after the call?
The case is outlined below:
g.DrawString(valueText, Font, new SolidBrush(Color.Red),

I am not entirely certain, but I don't believe it is. This would be safer:
using(var redBrush = new SolidBrush(Color.Red)
{
g.DrawString(valueText, Font, redBrush);
}

No, you should do it manually. Do however examine the classes Brushes and SystemBrushes, for ready-made brushes that you can use without creating new ones (and that you also don't need to / should not dispose).

Related

Windows Forms Parallel Drawing

Is it possible to draw on a panel using a Parallel.For loop? I have a multidimensional array of doubles, double[][] plants, and I want to draw the columns in parallel, where each entry in the array is drawn as a rectangle in a grid on the panel.
On the line with grapahics.FillRectangle(), I keep getting this error when I try:
An exception of type 'System.InvalidOperationException' occurred in System.Drawing.dll but was not handled in user code
Additional information: Object is currently in use elsewhere.
Here is the code I am using:
Parallel.For(0, simWidth, i =>
{
Color plantColor;
RectangleF plantRectangle= new Rectangle();
SolidBrush plantBrush = new SolidBrush(Color.Black);
for (int j = 0; j < simHeight; ++j)
{
int r, g = 255, b;
r = b = (int)(255 * (Math.Tanh(simulation.plants[i, j]) + 1) / 2.0);
plantColor = Color.FromArgb(100, r, g, b);
plantBrush.Color = plantColor;
plantRectangle.Location = new PointF(i * cellSize, j * cellSize);
graphics.FillRectangle(plantBrush, plantRectangle);
}
plantBrush.Dispose();
});
I think what is happening is that the graphics object cannot handle multiple calls at once. Is there any way around this? I tried creating a local reference to the graphics object in each parallel call but that did not work.
Is it possible to draw on a panel using a Parallel.For loop?
No, not in any way that would actually be useful.
UI objects, such as a Panel, have "thread affinity". That is, they are owned by a particular thread, and must only ever be used in that thread.
GDI+ objects, like your Graphics object (you don't say where you got that object, but one hopes it was passed to you in PaintEventArgsā€¦if not, you have other design flaws in your code) can be more forgiving, but are not thread-safe. You could add synchronization around the actual uses of the object, but those uses are the slow part. Serializing them will negate most of the benefit of concurrency in the code.
Your question does not make clear whether your use of Parallel here was even an actual attempt to address some specific performance problem, never mind what that problem actually was. There are numerous questions with answers on Stack Overflow that discuss various techniques for improving rendering performance in Windows Forms code.
In general, most of these techniques involve reducing the total amount of work done by caching as much as possible. Based on the code you've shown, there are at least two things you might want to do:
Cache the computations for the rectangles and colors. You can even do that part of the computation with Parallel, whenever the underlying parameters change.
Draw everything into a Bitmap object. This will have to be done single-threaded, but a) it doesn't have to be done in the UI thread that owns your UI objects, and b) you (again) can do this just once, whenever the underlying parameters change. Having drawn into a Bitmap, then you can just draw the Bitmap object when the Paint event occurs, instead of having to re-render everything from scratch.

Do I have to keep creating a Graphics object

I am an old delphi programmer, I am used to creating objects and using them entire time for efficient memory usage. But in c# (maybe all the tutorials I've ever seen), you are creating stuffs with new every time (thanks to garbage collector!!, let me do the coding)..
Anyway, I am trying to create a designing software which has lots of drawing.
My question is: do I have to create a graphics object, or use the protected override void OnPaint(PaintEventArgs e) e.Graphics every painting event.. because when I create a graphic object and then resize the control that I draw on, the graphic object that I created, has that clipping problem and only draws old rectangle region..
thanks
Caching objects makes sense when the object is expensive to create, cheap to store and relatively simple to keep updated. A Graphics object is unique in that none of these conditions are true:
It is very cheap to create, takes well less than a microsecond.
It is very expensive to store, the underlying device context is stored in the desktop heap of a session. The number of objects that can be stored is small, no more than 65535. All programs that run in the session share that heap.
It is very hard to keep updated, things happen behind your back that invalidates the device context. Like the user or your program changing the window size, invalidating the Graphics.ClipBounds property. You are wasting the opportunity to use the correct Graphics object, the one passed to you in a Paint event handler. Particularly a bug factory when you use double-buffering.
Caching a Graphics object is a bug.
If you want to draw on the surface always use the Graphics object from the Paint event!
If you want to draw into a Bitmap you create a Graphics object and use it as long as you want.
For the Paint event to work you need to collect all drawing in a List of graphic actions; so you will want to make a nice class to store all parameters needed.
In your case you may want to consider a mixed approach: Old graphic actions draw into a bitmap, which is the e.g. BackgroundImage or Image of your control
Current/ongoing drawing are done on the surface. This amounts to using the bitmap as a cache, so you don't have to redraw lots of actions on every little change etc
This is closely related to your undo/redo implementation. You could set a limit and draw those before into a Btimap and those after onto the surface..
PS: You also should rethink your GC attitude. It is simple, efficient and a blessing to have around. (And, yes, I have done my share of TP&Delphi, way back when they were affordable..) - Yes, we do the coding, but GC is not about coding but about house keeping. Boring at best.. (And you can always design to avoid it, but not with a Graphics object in a windows system.)
A general rule for every class that implements IDisposable is to Dispose() it, as soon as possible. Make sure you know about the using(...){} statement.
For drawing in WinForms (GDI+) the best practice is indeed to use the Graphics object from PaintEventArgs. And because you didn't create that one, do not Dispose() it. Don't stash it either.
I have to completely disagree with other more experienced members here who say it's no big deal or in fact better to recreate the Graphics object over and over.
The HDC is a pointer to a HDC__ struct, which is a struct with one member, "int unused". It's an absolute waste and stupidity to create another instance/object every time drawing needs to be done. The HDC is NOT large, it's either 4 or 8 bytes, and the struct it points to is in nearly all cases 4 bytes. Furthermore, on the point that one person made, it doesn't help that the graphics object be made with the "static" keyword at the beginning of the WndProc() before the switch, because the only way to give the Graphics object a device context or handle to paint on is by calling its constructor, so "static" does nothing to save you from creating it over and over again.
On top of that Microsoft recommends that you create a HDC pointer and assign it to the same value PAINTSTRUCT already has, every, single WM_PAINT message it sends.
I'm sorry but the WinAPI in my opinion is very bad. Just as an example, I spent all day researching how to make a child WS_EX_LAYERED window, to find out that in order to enable Win 8 features one has to add code in XML with the OS's ID number to the manifest. Just ridiculous.

Using with Font to set TextBox font

I'm building a C# Gui. Included in it is a Refresh event which gets called every second or so to refresh the screen.
private void RefreshEverySecond_Tick(object o, EventArgs a)
{
if (Condition1)
{
QuickStatusTextBox.Text = "Condition 1";
QuickStatusTextBox.Font = new Font(QuickStatusTextBox.Font, FontStyle.Bold);
}
else
{
QuickStatusTextBox.Text = "Condition 2";
QuickStatusTextBox.Font = new Font(QuickStatusTextBox.Font, FontStyle.Regular);
}
}
In researching the way to do this, I've seen answers like this which encourage this behavior:
Easiest way to change font and font size with visual C#
BUT I've also seen a lot of chatter saying I should be using "Using" for IDisposable objects which I gather Font is.
When should I use "using" blocks in C#?
And examples of using with fonts:
http://msdn.microsoft.com/en-us/library/yh598w02.aspx
Question: What is the right way to change a text box from Bold to Regular at periodic intervals? Does my method violate any rules or risk a memory leak or contention because I'm not using "using", and is there a "proper" way using Using? Remember this updates every second... so I'm likely keeping the Garbage collector busy but what other side effects are going to bite me?
A Font object in Winforms .NET actually encapsulates two things: a description of a typeface, and a handle to a GDI object which represents that typeface. One of those things represents a limited resource (the GDI handle) and the other does not.
While it might have been possible to have controls use the GDI handles of fonts which are used to set their properties, built-in controls do not do so. Instead, the line myControl.Font = myFont; will cause myControl to capture a description of the typeface encapsulated by myFont and make its own Font object for internal use. The control will ensure that its internal-use Font object gets disposed when either the control is disposed or its myControl.Font is set to a different font, but the control will neither dispose myFont nor care about when or whether it is disposed. Interestingly, it won't care if myFont had been disposed even before the statement above executed. Assuming nothing else has written it, reading myControl.Font will return a reference to myFont rather than the control's internal font object; if myFont has been disposed, then myControl.Font will return a reference to a font object which has been disposed (but could still be used to set other controls' Font properties).
If one wishes to most accurately ensure the prompt cleanup of GDI font resources, any font objects which will be used only as "templates" and won't be used for actual drawing may be disposed as soon as they are created. I don't know whether that should be recommended as a pattern, since I can't find any official documentation of controls' Font behavior, but it seems wasteful to have font objects holding GDI resources that are never going to be used. It's too bad controls' Font property doesn't use some sort of documented FontDescription class which would encapsulate just the typeface description but not the GDI handle, since such a design would make things a lot clearer.

How to properly draw a GeometryDrawing on a Canvas in WPF (performance-wise)

A few days ago I asked the following question:
How to draw graphics as efficiently as possible in WPF
The consensus was that using a Canvas as host-object in combination with GeometryDrawing classes I had nothing to fear performance-wise.
Though, after implementing a simple test, I came to the conclusion the application chokes on only 3000 of those objects on-screen.
During the implementation, I noticed I had to encapsulate a GeometryDrawing object in 2 different objects (DrawingImage and Image) before I could make the Canvas render it, I think this is where the chokepoint is. Below is an example code on how I do this currently:
//Node
GeometryDrawing geoNode = new GeometryDrawing(
new SolidColorBrush(Utils.IntToColor(graphNode.Color)),
new Pen(Brushes.Black, graphNode.Thickness),
new EllipseGeometry(new Point(graphNode.Position.X, graphNode.Position.Y), 16, 16)
);
Image imageNode = new Image
{
Source = new DrawingImage(geoNode),
};
SetLeft(imageNode, graphNode.Position.X);
SetTop(imageNode, graphNode.Position.Y);
Children.Add(imageNode);
My questions are:
Is encapsulating the GeometryDrawing objects the proper method to get them rendered?
Is there a faster way to display my GeometryDrawing objects without having to encapsulate them (eg. something else than Canvas)?
Am I expecting too much if I want good performance with 3000 on-screen objects using WPF? It doesn't seem like a high-number to me, as a proper 2D engine can render 10000 objects and still run smoothly. Besides, it has been pointed out that "under the hood" WPF uses DirectX.
Thanks!
I ended up using WPF for the interface and used SlimDX/XNA for the actual rendering. The library that came out of it this will be available some time later.

c# GDI+, Creating a LinearGradientBrush in a loop (memory leaks)

Today I came across a bit of a dilema. I have created an app that uses GDI+ to draw on a form. The drawing is triggered by a timer every second. The draw method uses a for loop to iterate through a collection of objects and if they are of a certain state, draw them.
I want to draw them using a LinearGradientBrush simply because it looks so much nicer than a simple Brush. Have a look at the following
//minutes
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = new LinearGradientBrush
(l.LedRectangle, Color.GreenYellow, Color.Green, 110);
if (l.IsLit)
g.FillRectangle(b, l.LedRectangle);
b.Dispose();
}
I am creating a new LinearGradientBrush for each iteration of the loop (which bothers me), but thats because I have to. I cannot create one outside the loop because its constructor set demands that I set parameters which are only ever known inside the loop.
I find that using the dispose method on the LinearGradientBrush object is not all that reliable. If I run my app and view it in Task manager, its spewing memory. When I then add the b = null line that seems to help hugely as follows
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = new LinearGradientBrush
(l.LedRectangle, Color.GreenYellow, Color.Green, 110);
if (l.IsLit)
g.FillRectangle(b, l.LedRectangle);
if (b != null)
{
b.Dispose();
b = null;
}
}
I am just wondering if there is a better way to work with LinearGradientBrushes ? Or is there a better solution to use ?
Many thanks
I would recommend using a "using" statement:
foreach (Led l in MinuteGrid.Leds)
{
if (l.IsLit)
{
using(LinearGradientBrush b = new LinearGradientBrush(l.LedRectangle, Color.GreenYellow, Color.Green, 110))
{
g.FillRectangle(b, l.LedRectangle);
}
}
}
However, remember, Dispose() does not free (managed) memory. It just releases the unmanaged resources (which is important, and may include unmanaged memory). The memory will not free until the GC runs, which may not happen during your loop.
However, if the memory pressure gets too high, the garbage collector should run within your loop, and you'll see it drop. This is the way .NET is designed - just accept it, and don't worry. The GC will eventually collect this memory, so its not something to worry about.
Add a gradient brush to each Led.
If you can't add it to that class, then you could use a Dictionary<Led,GradientBrush> to store the brushes in to gain easy access to them.
That way you only need one brush per Led instead of one per loop iteration,
(Also, in your example code, there is no point creating the brush if !l.IsLit)
Dispose has nothing to do with freeing managed memory. That is handled entirely by GC, which runs "when needed". However, since the brush most likely holds a handle, you should dispose it. I would recommend that you do that in a using block instead of manually calling Dispose as this will make sure Dispose is called even in the presence of an exception.
If the number of permutations is limited you might just pre-create all your brushes once:
LinearGradientBrush rectGreenBrush = new LinearGradientBrush(l.LedRect........);
LinearGradientBrush rectRedBrush = new LinearGradientBrush(l.LedRect........);
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = null;
if (xxx)
b = rectGreenBrush;
else if (yyyy)
b = rectRedBrush;
else.....
do painting
}
cleanup brushes
A second option is similar, but to create the brushes as needed;
List<LinearGradientBrush> createdBrushes = new List<LinearGradientBrush>();
foreach (Led l in MinuteGrid.Leds)
{
LinearGradientBrush b = null;
b = FindOrCreateBrushBasedOnLed(l, createdBrushes);
// if not already created, creates the brush and adds it to the list
do painting
}
foreach (LinearGradientBrush b in createdBrushes)
{
cleanup brushes
}
The other answers are correct that .NET may allow managed memory usage to balloon as long as it's not harming anything. But this should help cut out a lot of the creating/deleting if there are many Led objects to loop through.

Categories

Resources