Confessions of a .NET Developer!

Saving forms settings(location, height) using Serialization

In some applications, there might be some requirements
where you have to load last used form settings like Location, Height and Width the next time you open the form. Well you can create an XML Document with attributes like Location, Width and Height and save it at some location. And then use the XMLDocument class to load and traverse the XML to retrieve the settings. I will bring another, easy way; by using Serialization.

I won’t be going to the details of what Serialization or Deserialization is, as it can be found in many introductory C# books and online tutorials. The only purpose here is to show how can I put Serialization to use.

Basically there are three types of Serialization:
1) BinaryFormatter
2) SoapFormatter
3) XMLFormatter

I will be using Soap as this is the preferred way to persist the object state to be used by any operating system or any framework. XMLFormatter is also a choice but it cannot serialize private fields.

Alright let’s get started.

First create a Windows Forms application and add the following labels as shown in the window.

Labels

Labels

These labels will show the location, height and width of the form to be crossed checked later when we next time open the form.

Next we will create a class named FormSettings whose object we want to persist. As we are using Serialization, this class will be a serialized class by specifying the [Serializable] attribute on top of the class declaration.
The class will look like this:

    [Serializable]
    class FormSettings
    {
        public Point FormLocation { get; set; }
        public FormWindowState WindowState{ get; set; }
        public int Height { get; set; }
        public int Width { get; set; }

        public FormSettings(Point _formLoc, FormWindowState _windowState, int _height, int _width)
        {
            FormLocation = _formLoc;
            WindowState = _windowState;
            Height = _height;
            Width = _width;
        }
    }

Lets get back to the code-behind of our form.
We will declare two private string fields, dirPath and filePath and and four event handlers as shown below.

    public partial class Form1 : Form
    {
        string dirPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) +
            @"\FormSettings\";

        string filePath;

        public Form1()
        {
            InitializeComponent();

            this.Load += new EventHandler(Form1_Load);
            this.FormClosed += new FormClosedEventHandler(Form1_FormClosed);
            this.Move += new EventHandler(Form1_Move);
            this.Resize += new EventHandler(Form1_Resize);
        }

dirPath is the folder where we will keep the file which in turn will store FormSettings class’s object’s data.

Let’s first discuss the Move and Resize event:

        void Form1_Move(object sender, EventArgs e)
        {
            lblX.Text = this.Location.X.ToString();
            lblY.Text = this.Location.Y.ToString();
        }

        void Form1_Resize(object sender, EventArgs e)
        {
            lblHeight.Text = this.Height.ToString();
            lblWidth.Text = this.Width.ToString();
        }

Whenever our form is moved or resized, the labels will update the current location and width and height accordingly.

Now let us discuss the Load event.

        void Form1_Load(object sender, EventArgs e)
        {
            LoadSettings();
        }

        private void LoadSettings()
        {
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            filePath = dirPath + @"\Settings.dat";

            if (File.Exists(filePath))
            {
                using (FileStream stream = new FileStream(filePath, FileMode.Open,
                    FileAccess.Read, FileShare.None))
                {
                    SoapFormatter sf = new SoapFormatter();
                    FormSettings settings = (FormSettings)sf.Deserialize(stream);

                    this.Location = settings.FormLocation;

                    if (settings.WindowState == FormWindowState.Maximized)
                    {
                        this.WindowState = FormWindowState.Maximized;
                    }
                    else
                    {
                        this.Width = settings.Width;
                        this.Height = settings.Height;
                    }
                }
            }
        }

Seems to be quite big but its simple.

Scenario 1: When the form is loaded for the very first time.

When the form is loaded for the very first time, it will create a Folder named FormSettings in CommonApplicationData(where all the users can share) directory. And the Settings.dat is appended to the dirPath creating a filePath string. But wait, as it is loaded for the very first time, we don’t have any previous data of location, width or height, hence no need to create the Settings.dat file.

We will create this file in the Closed event as shown below.

Next let us discuss the Closed event.

        void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            SaveSettings();   
        }

        private void SaveSettings()
        {
            FormSettings settings = new FormSettings(this.Location, this.WindowState, 
                this.Height, this.Width);

            using (FileStream stream = new FileStream(filePath, FileMode.Create, 
                FileAccess.ReadWrite, FileShare.None))
            {
                SoapFormatter sf = new SoapFormatter();
                sf.Serialize(stream, settings);
            }
        }

After moving and adjusting the height(to lets say 300), width(250) and location(50,50) (remember that we are considering scenario 1), let’s close the form. Before closing it, we need to save the location(50,50) and other settings to Settings.dat. But as we don’t have the file created, we will create it now by giving FileMode.Create enum which will create if the file doesn’t exist. Now that our file has been created, we will create an instance of SoapFormatter class and use the Serialize method to save the object in that file.
So what happened in our first scenario is that, the file got created and last used location(50,50), height(300) and width(250) got saved as FormSettings object in that file.
Below is the image showing the form position at (50,50).

Scenario1

Scenario1

Scenario2: Opening the form for the nth time.
Let’s again open the form. So the Load event will be called which in turn will call the LoadSettings function.
Let’s again have a look at it:

        private void LoadSettings()
        {
            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            filePath = dirPath + @"\Settings.dat";

            if (File.Exists(filePath))
            {
                using (FileStream stream = new FileStream(filePath, FileMode.Open,
                    FileAccess.Read, FileShare.None))
                {
                    SoapFormatter sf = new SoapFormatter();
                    FormSettings settings = (FormSettings)sf.Deserialize(stream);

                    this.Location = settings.FormLocation;

                    if (settings.WindowState == FormWindowState.Maximized)
                    {
                        this.WindowState = FormWindowState.Maximized;
                    }
                    else
                    {
                        this.Width = settings.Width;
                        this.Height = settings.Height;
                    }
                }
            }
        }

When the program execution reaches this function, first it will check whether our directory exists. Yes it does exist when we first run the form before. Then it checks whether the file exists. Again yes it does exist, we created it when we first run the form and created on the Close event.
So now it enters the if(FileExists…) condition. We open the file using FileStream, create the SoapFormatter object and “deserialize” the FormSettings object from the stream. The deserialize method returns an object, hence we have to cast it to FormSettings, lets say the name of the FormSettings object is settings. Retrieve the FormLocation(50,50), width(250) and height(300) of the form from the settings object and set the form’s location, width and height accordingly. So now we got the last used the Width, Height and Location of the form. Excellent.
Below is the snapshot showing the form at (50,50) which was the location that was opened last time.

Scenario2(AfterOpening)

Scenario2 (After Opening)

Now play around with the form, change the location to (100,100) , width to 400, location to 500 and then close it. Now when we close it, SaveSettings function will be called, we need to store the settings that we changed just now back to the file.
Lets have a look at the SaveSettings function now:

        private void SaveSettings()
        {
            FormSettings settings = new FormSettings(this.Location, this.WindowState, 
                this.Height, this.Width);

            using (FileStream stream = new FileStream(filePath, FileMode.Create, 
                FileAccess.ReadWrite, FileShare.None))
            {
                SoapFormatter sf = new SoapFormatter();
                sf.Serialize(stream, settings);
            }
        }

Just to remind ourselves, we now need to store the location(remember 100,100?) and other settings which we just changed back to the file so that the next time the form is opened, the location of the form should be at (100,100).
The interesting thing is that, FileMode.Create won’t actually create another file, as our file already exists, it will instead overwrite the already present data and that is what we wanted! to store the new location(100,100).
So the serialize method will store the settings into the file. So when AGAIN when you open the form, the form will be set at 100,100.

Oh almost forgot, also check out the WindowState property. If it is maximized, then we don’t need the height and width of the form. Hence the next time the window opens, it will be in the maximized state only.

Phew! That’s it! Have fun playing around with it.
Do let me know if there is any kind of bugs that you found.
Cheers!

Advertisements

July 5, 2011 Posted by | C Sharp, Winforms | 1 Comment