Click here to Skip to main content
Click here to Skip to main content

Preferences Form Settings Dialog

, 27 Mar 2012
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Fabrizio Stellato
Software Developer (Senior)
Italy Italy
Creator of:
Impulse Media Player http://impulsemediaplayer.codeplex.com
Audio Pitch & Shift http://audiops.codeplex.com
Ultimate Music Tagger http://umtagger.codeplex.com
Modern Log Viewer http://modernlogviewer.codeplex.com
Pitch Tuner http://pitchtuner.codeplex.com
Follow on   LinkedIn

Comments and Discussions

 
QuestionWorks Great PinmemberLuis Ricardo Delgado Cortés12-Feb-14 16:59 
AnswerRe: Works Great PinmemberFabrizio Stellato12-Feb-14 22:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140709.1 | Last Updated 27 Mar 2012
Article Copyright 2012 by Fabrizio Stellato
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid