Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Preferences Form Settings Dialog

0.00/5 (No votes)
27 Mar 2012 1  
How to build a standard preferences Form with tree node and content columns.

Introduction

A lot of desktop applications use a typical preferences dialog composed by a section node menu and the relative content selected on the right. 

Let's see how make it.

Using the code

First off, we start creating a form, an horizontal split container within a tree view and a TableLayoutPanel on the right columns.

Then we place two buttons, Save and Close on the bottom part of the TableLayoutPanel content.

This will look like this: 

Typically, every single panel called by the menu section will have inside code for saving, validating and load settings at startup.

This is all granted by this interface

interface IUserControlPrefPanel
{
    bool IsValid();
    void Save();
    void LoadSettings();
} 

Now we can start building up all custom panels needed using User Control and our interface IUserControlPrefPanel.

Once designed all the panels and implemented the three functions for each of these, the main form will have a code like this

public Form1()
{
    InitializeComponent();
}

private UserControlPanelN0 userControlPanelN0 = new UserControlPanelN0();
private UserControlPanelN1 userControlPanelN1 = new UserControlPanelN1();

private UserControl mActivePanel;

private bool statusChanged = false;

private void Form1_Load(object sender, EventArgs e)
{
    userControlPanelN0.LoadSettings();
    userControlPanelN1.LoadSettings();

    userControlPanelN0.Visible = false;
    userControlPanelN1.Visible = false;

    treeViewMenu.SelectedNode = treeViewMenu.Nodes[0];

    AddEnableSaveOnChanges(userControlPanelN0);
    AddEnableSaveOnChanges(userControlPanelN1);
}

private void AddEnableSaveOnChanges(Control obj)
{
    foreach (Control control in obj.Controls)
    {
        control.TextChanged += EnableSave;

        // some events can occurs with your controls inside panel
        if (control.GetType() == typeof(CheckBox))
        {
            ((CheckBox)control).CheckedChanged += EnableSave;
        }

        if (control.GetType() == typeof(ListView))
        {
            ((ListView)control).SelectedIndexChanged += EnableSave;
        }

        // containers
        if (control.Controls.Count > 0)
            AddEnableSaveOnChanges(control);
    }
}

private void EnableSave(object sender, EventArgs e)
{
    statusChanged = true;
    this.buttonSave.Enabled = true;
}

private void treeViewMenu_AfterSelect(object sender, TreeViewEventArgs e)
{            
    UserControl newPanel = null;
    switch (e.Node.Index)
    {
        case 0: newPanel = userControlPanelN0; break;
        case 1: newPanel = userControlPanelN1; break;
        // etc...
    }
    if (newPanel != null)
    {
        if (mActivePanel != null)
        {
            mActivePanel.Hide();
            this.Controls.Remove(mActivePanel);
        }
        newPanel.Show();
        newPanel.Dock = DockStyle.Fill;                
        tableLayoutPanelRight.Controls.Add(newPanel);
        tableLayoutPanelRight.SetColumnSpan(newPanel, 2);

        mActivePanel = newPanel;
    }        
}

private void buttonCancel_Click(object sender, EventArgs e)
{
    bool exit = !statusChanged;

    if (!exit)
        if (MessageBox.Show("Settings changed, close anyway?", 
                "Confirm exit", MessageBoxButtons.YesNo, 
                MessageBoxIcon.Question) == DialogResult.Yes)
            exit = true;

    if (exit)
        this.Close();
}

private void buttonSave_Click(object sender, EventArgs e)
{
    bool isValid = true;

    isValid = isValid && userControlPanelN0.IsValid();
    isValid = isValid && userControlPanelN1.IsValid();

    if (isValid)
    {
        userControlPanelN0.Save();
        userControlPanelN1.Save();
        buttonSave.Enabled = false;
    }
    else
        MessageBox.Show("No valid settings specified", "ERROR", 
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Notice that AddEnableSaveOnChanges take all the interested controls inside the panel binding the EnableSave function on any value changes. 

Here are some previews:

That's all!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here