Other DevExpress WinForms Cheat Sheets
This article explains how to avoid memory and resource leaks. Among many reasons that cause memory leaks, the most common is not calling the Dispose method to destroy objects that are no longer needed. The list below explains how to avoid this and other common issues:
-
Classes that implement the IDisposable interface (Stream, Graphics, File, etc.) typically use unmanaged resources. To release these resources, call the Dispose method before you release your last reference to an object of such a class. If the object is declared within a method, wrap its declaration in the "using" statement - the Dispose method will be called automatically when the object is not needed.
-
Unsubscribe from events when a handler is no longer required. The publisher of the event holds a reference to the subscriber via the event handler delegate when an event handler is subscribed. If the publisher lifetime is longer than the subscriber lifetime, the publisher will keep the subscriber alive even if there are no references to it. So, you need to unsubscribe an event handler from the event to remove a reference and avoid a possible leak. However, if the publisher and subscriber have equal lifetimes, you do not need to worry about unsubscribing from an event.
Refer to the following articles to learn more about event handling:
How to subscribe to and unsubscribe from events (C# Programming Guide)
Events (Visual Basic) -
Dispose of closed modal forms that are no longer needed. Unlike non-modal forms that are destroyed when users click the Close button, modal forms become hidden but still exist. This allows you to restore hidden modal forms without making new instances of them. If that is not needed, call the Dispose method for hidden modal forms.
Refer to the MSDN article for more details:
Form.ShowDialog Method -
Be aware of static and long-live objects' lifetime. Static objects are GC Roots and are never collected by the garbage collector. Thus, an object itself and everything it references will never be collected. Objects rooted at the level of a long-live object also may be not garbage collected for a long time (their lifetime is equal to the lifetime of this long-live object). For example, a variable at the main form level will not be collected until an application is closed.
Best Practices
Change the control/element font
Font is the IDisposable object that should be disposed of before you release your last reference to it. When our components are used, most often it is required to change the font in an event handler that is raised many times (for example, GridView.RowCellStyle). Therefore, creating a new font each time an event is raised leads to a memory leak.
However, our AppearanceObject has the FontStyleDelta and FontSizeDelta properties for modifying the font size and style. These properties will allow you to modify an existing font instead of creating a new one, so you won't have to worry about disposing resources in this case:
C#private void GridView_RowCellStyle(object sender, DevExpress.XtraGrid.Views.Grid.RowCellStyleEventArgs e)
{
if (e.RowHandle % 2 == 0)
{
e.Appearance.FontStyleDelta = FontStyle.Italic;
e.Appearance.FontSizeDelta = 5;
}
}
Correct creation of a new font in specific cases
For some specific cases, the FontStyleDelta and FontSizeDelta properties are not enough and a new font should be set (for example, you need to change FontFamily). In this case, do not create a font multiple times (when you set it in a method that can be called multiple times, it might happen unintentionally). Create a font once and use it in the required methods:
C#public Form1()
{
InitializeComponent();
myFont = new Font("Arial", 15);
...
}
...
Font myFont;
private void GridView_RowCellStyle(object sender, DevExpress.XtraGrid.Views.Grid.RowCellStyleEventArgs e)
{
if (e.RowHandle % 2 == 0)
e.Appearance.Font = myFont;
}
Creation of Drawing objects
Most often, when working with our components, you need to create Pens and Brushes to custom draw a control's elements. In this case, obtain a Drawing object from AppearanceObject by using the following methods:
GetBackBrush(GraphicsCache)
GetForeBrush(GraphicsCache)
GetBackPen(GraphicsCache)
GetForePen(GraphicsCache)
With this approach, you don't have to worry about disposing of resources, and you will also get consistent colors in custom painting, since these methods return Pens and Brushes of the current control appearance settings:
C#private void GridView_CustomDrawGroupPanel(object sender, DevExpress.XtraGrid.Views.Base.CustomDrawEventArgs e)
{
e.Cache.FillRectangle(e.Appearance.GetBackBrush(e.Cache), e.Bounds);
...
}
Creation of Drawing/Graphics objects other than those contained in AppearanceObject or outside of the painting methods (for example, how to correctly create GraphicsCache to calculate text size)
In this case, you need to create such an object by using the 'using' statement:
C#using (GraphicsCache cache = grid.CreateGraphicsCache())
{
view.Appearance.Row.CalcTextSizeInt(cache, "text", 75);
}
Correct subscription to an event in a method that can be called many times
In this case, you need to unsubscribe from the event before calling the method again. For example, you subscribe to a popup form event in PopupBaseEdit.Popup that is raised after the editor's popup window has been opened. So, you need to unsubscribe from a popup form event when a popup is closed:
C#private void SearchLookUpEdit1_Popup(object sender, EventArgs e)
{
var edit = sender as SearchLookUpEdit;
var popupForm = edit.GetPopupEditForm();
popupForm.KeyUp += PopupForm_KeyUp;
}
private void SearchLookUpEdit1_Closed(object sender, DevExpress.XtraEditors.Controls.ClosedEventArgs e)
{
var edit = sender as SearchLookUpEdit;
var popupForm = edit.GetPopupEditForm();
popupForm.KeyUp -= PopupForm_KeyUp;
}