Automatically Settings Class for Saving and Loading

This is a class helper that will make it easier to save and load settings.

The class gathers information from any given control, creates a key, type, and value, and writes the information to a Json file.

This is an example of the json file content after saving.

{
  "textBoxLensSize": "1000",
  "checkBoxDrawBorder": false,
  "checkBoxSaveCroppedImages": true,
  "checkBoxClearShapes": true
}

The key names are the control names given to the designer by the user. And on the right, it's the values and states.

This is the class code.

using Images_Cropping.Properties;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;

namespace Images_Cropping
{
    public class MySettings
    {
        private Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
        private string jsonFilePath;

        public MySettings(string filePath)
        {
            jsonFilePath = filePath;
        }

        public void LoadSettings()
        {
            if (File.Exists(jsonFilePath))
            {
                string json = File.ReadAllText(jsonFilePath);
                keyValuePairs = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
                ApplySettingsToControls();
            }
        }

        public void SaveSettings(Control control)
        {
            // Store the control information in the dictionary
            string controlName = control.Name; // Store the control name separately
            keyValuePairs[controlName] = GetControlValue(control); // Use controlName as the key

            // Save settings to the JSON file
            SaveSettingsToFile();
        }

        public void SaveSettingsToFile()
        {
            string json = JsonConvert.SerializeObject(keyValuePairs, Formatting.Indented);
            File.WriteAllText(jsonFilePath, json);
        }

        private void ApplySettingsToControls()
        {
            List<string> keysToRemove = new List<string>();

            foreach (var key in keyValuePairs.Keys.ToList()) // Create a copy of keys
            {
                string controlName = key; // Get the control name directly
                Control control = FindControlByNameRecursive(controlName);

                if (control == null)
                {
                    keysToRemove.Add(controlName); // Add to remove list
                    continue; // Skip controls not found
                }

                // Determine the property type and set the value accordingly
                if (keyValuePairs[key] is bool boolValue)
                {
                    if (control is CheckBox checkBox)
                    {
                        checkBox.Checked = boolValue;
                    }
                }
                else if (keyValuePairs[key] is string textValue)
                {
                    if (control is TextBox textBox)
                    {
                        textBox.Text = textValue;
                    }
                }
                // Add more control types and properties as needed
            }

            // Remove keys for controls that were not found
            foreach (string keyToRemove in keysToRemove)
            {
                keyValuePairs.Remove(keyToRemove);
            }
        }

        private Control FindControlByNameRecursive(string name)
        {
            return FindControlByNameRecursive(Application.OpenForms[0], name);
        }

        private Control FindControlByNameRecursive(Control parentControl, string name)
        {
            if (parentControl.Name == name)
            {
                return parentControl;
            }

            foreach (Control control in parentControl.Controls)
            {
                Control foundControl = FindControlByNameRecursive(control, name);
                if (foundControl != null)
                {
                    return foundControl;
                }
            }

            return null;
        }

        private object GetControlValue(Control control)
        {
            if (control is CheckBox checkBox)
            {
                return checkBox.Checked;
            }
            else if (control is TextBox textBox)
            {
                return textBox.Text;
            }
            // Handle other control types as needed

            return null;
        }
    }
}

Then it's very simple and easy to use anywhere in the project. For example, in form 1.

First, we declare the class and create an instance in the constructor.

private MySettings mySettings;

public Form1()
{
    InitializeComponent();
    
    // Initialize your module classes here
    mySettings = new MySettings(@"d:\settings.json");
}

Now we can save anything we want. For example, the value in a textbox controls changed events.

private void textBoxLensSize_TextChanged(object sender, EventArgs e)
{
    // Perform real-time input validation
    if (int.TryParse(textBoxLensSize.Text, out int width))
    {
        // Valid integer input
        if (width >= 10)
        {
            LensCropRectWidth = width; // Update the property

            if (!isFirstTimeSettingLensSize)
            {
                mySettings.SaveSettings(textBoxLensSize);
            }
            else
            {
                isFirstTimeSettingLensSize = false;
            }
        }
        else
        {
            // Show a message if the value is less than 10
            MessageBox.Show("Please enter a value greater than or equal to 10.");
            textBoxLensSize.Text = 10.ToString(); // Revert to the previous value
            labelCroppedImagesCount.Focus();
        }
    }
}

One single line for saving, no need to give names, no need to give any too many parameters.  

mySettings.SaveSettings(textBoxLensSize);

Another example, this time, we are saving a checkbox control state:

private void checkBoxRectangleCropping_CheckedChanged(object sender, EventArgs e)
{
    if (checkBoxRectangleCropping.Checked)
    {
        // Check if Rectangle Cropping is selected
        // Uncheck the other cropping mode checkboxes
        checkBoxRealTimeCropping.Checked = false;
        checkBoxFreeRoamCropping.Checked = false;

        // Perform actions for Rectangle Cropping mode
        radioButtonTriangle.Enabled = false;
        radioButtonCircular.Enabled = false;
        radioButtonRectangular.Enabled = false;

        // Ensure originalImage is not null before calling CropImage
        if (originalImage != null)
        {
            CropImage(CropMode.Rectangles, RealTimeSubMode.None);
        }
    }

    // Update the appearance of the selected items
    UpdateSelectedCroppingModeAppearance();

    mySettings.SaveSettings(checkBoxRectangleCropping);
}

Again, we are given a simple single line with the control name, and the class will do all the jobs for us.

The last thing is loading.  We are going to load back everything to the controls, the values, and the states inside the form1 shown form. 

We want to wait first for the form to be loaded and then load back the settings. And again, with one simple line.

private void Form1_Shown(object sender, EventArgs e)
{
    mySettings.LoadSettings();
}

It couldn't be easier.

Two things to remember.

1. In the form1 constructor, when creating an instance for the class, enter your own path and file name where you want to save the settings file.

// Initialize your module classes here
mySettings = new MySettings(@"d:\settings.json");

2. In the class itself in MySettings.cs I'm currently handling only textboxes and checkbox control types. But as you can see in the code, it's very easy to add any other controls if you need them.

  • Depending on your project and what controls you have in the form that you want to save information.
  • In line 77 // Add more control types and properties as needed. Just add another one if you need any control. You need.
  • In line 121 // Handle other control types as needed. Just follow the code above it and add any control handler.
  • The reason that I didn't add in both laces the code for all the existing controls is because it's too much code, and it's better that the user will add only the control he needs to use.


Similar Articles