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;
if (control.GetType() == typeof(CheckBox))
{
((CheckBox)control).CheckedChanged += EnableSave;
}
if (control.GetType() == typeof(ListView))
{
((ListView)control).SelectedIndexChanged += EnableSave;
}
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;
}
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!