Browse DevX
Sign up for e-mail newsletters from DevX


Exploring Secrets of Persistent Application Settings : Page 2

The .NET framework makes it easier than ever to create application settings and bind them to controls, but you need to know a few secrets to go beyond basic string settings and avoid problems.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Exploring the Sample GUI Application
Figure 5 shows the simple GUI for the sample application described in this article to illustrate using various settings.

Figure 5. Sample GUI: Here's a design-time view of the sample application.
The application will fill in the "TBD" text shown in labels and text box fields at runtime. The DataGridView, shown with a single column in Figure 5, provides a visual outlet for the ItemList ArrayList created earlier. The Save button is there as a convenience; you could use it to update persistent settings without quitting the program (it will call exactly the same method that is called when actually quitting).

Typically, you want to access settings from Windows Forms during specific events, such as startup, shutdown, or to respond to specific user events. The code below shows all three types:

public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { SaveToFile(); } private void saveButton_Click(object sender, EventArgs e) { SaveToFile(); } private void Form1_Load(object sender, EventArgs e) { LoadDataGridView(myDataGridView); preferredPathTextBox.Text = Properties.Settings.Default.PreferredPath; lastRunTimeLabel.Text = Properties.Settings.Default.LastRunTime.ToString(); domainLabel.Text = Properties.Settings.Default.PlanetarySystem; } private void SaveToFile() { Properties.Settings.Default.ItemList = DGVtoList(); Properties.Settings.Default.PreferredPath = preferredPathTextBox.Text; Properties.Settings.Default.LastRunTime = DateTime.Now; Properties.Settings.Default.Save(); } }

Author's Note: I have omitted the DGVtoList and LoadDataGridView methods referenced in the preceding code, as they are not germane to the main focus, but they are available in the sample project code.

As noted earlier, terminating the program (form closing event) and clicking the Save button (button click event) both call the SaveToFile method.

When the form loads, it populates the TextBox, the two Labels, and the DataGridView from the values available in the application settings. These are automatically loaded by the .NET framework from the application configuration file. You access them via the Properties.Settings.Default.<name> notation that you see in the code. Note that the settings are strongly typed. Thus, to set the Text property of the Label to the DateTime object stored in the LastRunTime setting, you must invoke its ToString method.

If you compile your project as an executable (.exe), its configuration file—stored in the same directory—will be called app.exe.config, where "app" is the name of your executable file. Recall that settings may be application-scoped or user-scoped. All application-scoped settings reside in the app.exe.config file. User-scoped settings are also in the app.exe.config file initially; the .NET framework loads them from app.exe.config the very first time you execute the program—and continues to load them from that file as long as you do not save any changed user-scoped settings.

Looking now at the SaveToFile method, note that it simply makes assignments into Properties.Settings.Default.<name>. However, it stores only the user-scoped ItemList, PreferredPath, and LastRunTime settings, not the PlanetarySystem setting, because that's application-scoped and immutable. The last line of the method invokes the Settings.Save method, causing the framework to:

  • Determine if any settings have indeed been changed.
  • Check if the user-scoped settings file exists and if not create it.
  • Write the current values of the user-scoped settings to the user's settings file (user.config).
Executing the Sample Application
With the settings code in place, Figure 6 shows the application when it first launches.

Figure 6. First Launch: When you launch the application for the first time, you can see the default values appear in the Domain and Preferred Path fields, but the Last Run Time value is obviously incorrect, and the DataGridView is empty.
Figure 7. Second Launch: After closing the application, the Last Run Time value was saved and now displays properly upon a subsequent launch.
Remember that the application settings contain initial values for the PlanetarySystem and PreferredPath strings but not for the DateTime or the ArrayList settings. So, at first launch, the Last Run Time then shows the textual representation of no value and, as the ArrayList is empty, so is the DataGridView. Now terminate the program and then restart it, and it will look like Figure 7.

Closing the form runs the SaveToFile() method, which records the date and time when you terminated the program, creating a user.config file containing the new value for the user-scoped setting. Restarting the program recalls that persistent value and will never again show the default (null) unless and until you delete or rename the user-scoped settings file. This file, by the way, is always called just user.config. Unlike the application-scoped setting file app.exe.config, which is stored in the same folder as the executable, the location of user.config is much more convoluted. A typical path will be something like:

\Documents and Settings\your-user-name\Local Settings\ Application Data\your-company-name\app_xxx_yyy\\user.config

More generally the path format is:

<Profile Directory>\<Company Name>\<App Name>_<Evidence Type>_<Evidence Hash>\<Version>\user.config

See the description of the components of this path at the Client Settings FAQ.

Here's the user.config file created when the program terminated for the first time:

<?xml version="1.0" encoding="utf-8"?> <configuration> <userSettings> <AppSettings.Properties.Settings> <setting name="PreferredPath" serializeAs="String"> <value>C:\</value> </setting> <setting name="LastRunTime" serializeAs="String"> <value>02/27/2007 15:32:02</value> </setting> <setting name="ItemList" serializeAs="Xml"> <value> <ArrayOfAnyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /> </value> </setting> </AppSettings.Properties.Settings> </userSettings> </configuration>

Figure 8: Modifying Values: The Preferred Path value has been modified, and several items were added to the DataGridView.
Note that the framework writes all the settings even though only one actually changed. The PreferredPath in this file still has the same value as the PreferredPath setting in the app.exe.config file, and the ItemList is still empty.

So, with the application still running, go ahead and enter a few values in the ItemList and change the path, as shown in Figure 8.

Press Save and then look at user.config again, which now looks something like this:

<?xml version="1.0" encoding="utf-8"?> <configuration> <userSettings> <AppSettings.Properties.Settings> <setting name="PreferredPath" serializeAs="String"> <value>C:\etc\data</value> </setting> <setting name="LastRunTime" serializeAs="String"> <value>02/27/2007 15:45:56</value> </setting> <setting name="ItemList" serializeAs="Xml"> <value> <ArrayOfAnyType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <anyType xsi:type="xsd:string">line one</anyType> <anyType xsi:type="xsd:string">123456</anyType> <anyType xsi:type="xsd:string">four score and 7yrs</anyType> </ArrayOfAnyType> </value> </setting> </AppSettings.Properties.Settings> </userSettings> </configuration>

That concludes the discussion of the basics of persistent settings. But it's possible to reduce the amount of code you have to write even further by binding application settings to form controls, giving you the automatic, two-way updates described at the start of this article.

Thanks for your registration, follow us on our social networks to keep up-to-date