tags:

views:

24

answers:

2

In a winforms application I have an options form. The form has a treview control and a panel control. Depending on the users choice in the treeview I want to load/add a usercontrol to the panel control. When should I be creating/initiating the usercontrols? On the form load eventhandler or once a treeview node is selected? And should I be disposing of the usercontrols in the from closing eventhandler?

This is my code:

public partial class Options : Form
{
    //usercontrols
    Connections _connections;
    Notifications _notifications;
    Proxy _proxy;

    private void Options_Load(object sender, EventArgs e)
    {
        treeViewOptions.ExpandAll();

        _connections = new Connections();
        _notifications = new Notifications();
        _proxy = new Proxy();
    }

    private void treeViewOptions_AfterSelect(object sender, TreeViewEventArgs e)
    {
        switch (treeViewOptions.SelectedNode.Name)
        {

            case "NodeConnection":
                ControlPanel.Controls.Clear();
                ControlPanel.Controls.Add(_connections);
                break;
            case "NodeNotifications":
                ControlPanel.Controls.Clear();
                ControlPanel.Controls.Add(_notifications);
                break;
            case "NodeProxy":
                ControlPanel.Controls.Clear();
                ControlPanel.Controls.Add(_proxy);
                break;
        }
    }
}

Thanks

+1  A: 

Yes, you need to fix this. Right now you are leaking the user controls instances, they won't get disposed automatically. Nor does their finalizer take care of the job. After a while, your program will crash when it has consumed 10,000 window handles.

Make it look similar to this:

private void treeViewOptions_AfterSelect(object sender, TreeViewEventArgs e)
{
    foreach (Control ctl in ControlPanel.Controls) ctl.Dispose();
    ControlPanel.Controls.Clear();

    switch (treeViewOptions.SelectedNode.Name)
    {

        case "NodeConnection":
            ControlPanel.Controls.Add(_connections);
            break;
        case "NodeNotifications":
            ControlPanel.Controls.Add(_notifications);
            break;
        case "NodeProxy":
            ControlPanel.Controls.Add(_proxy);
            break;
    }
}
Hans Passant
Ok thanks. Am I creating the controls at the right time though? Is it correct to create all the controls during form load or should I be creating them in my select cases?
Sam
Wouldn't it be better to dispose of the controls in the form closing eventhandler? Because the controls are created in the form load eventhandler which means the same control can be used if the user switches back and forth between the treview nodes. With your solution I'd have to create a new instance of the usercontrol everytime the user selected a new treeview node, which would surely be less performant?
Sam
You are using quite a bit less system resources when you create them on-the-fly. Perf shouldn't be noticeably affected. The cost is in the control painting itself, creation is cheap. One feature of keeping them alive and switching between them with Hide/Show is that anything entered in the controls previously stays preserved. Could be desirable, could not, it depends.
Hans Passant
If I recall right, Controls.Clear() will internally call Dispose() on each removed control.
Anna Lear
@Anna - it doesn't. A nasty trap that many winforms programmers have fallen into. It takes a while for the leak to crash the program.
Hans Passant
+1  A: 

Solution:

public partial class Options : Form
{
    //usercontrols
    Connections _connections;
    Notifications _notifications;
    Proxy _proxy;

private void Options_Load(object sender, EventArgs e)
{
    treeViewOptions.ExpandAll();

    _connections = new Connections();
    _notifications = new Notifications();
    _proxy = new Proxy();
}

private void treeViewOptions_AfterSelect(object sender, TreeViewEventArgs e)
{
    ControlPanel.Controls.Clear();

    switch (treeViewOptions.SelectedNode.Name)
    {

        case "NodeConnection":

            ControlPanel.Controls.Add(_connections);
            break;
        case "NodeNotifications":

            ControlPanel.Controls.Add(_notifications);
            break;
        case "NodeProxy":

            ControlPanel.Controls.Add(_proxy);
            break;
    }
}

   private void Options_FormClosing(object sender, FormClosingEventArgs e)
    {

        _connections.Dispose();          
        _notifications.Dispose();
        _proxy.Dispose();

    }

}

Sam