65.9K
CodeProject is changing. Read more.
Home

Preferences Form Settings Dialog

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.50/5 (3 votes)

Mar 26, 2012

CPOL
viewsIcon

15576

downloadIcon

308

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!