VB.NET My.Settings deep dive
Introduction
Visual Basic (VB.NET) provides developers with an object, My.Settings which provides access to application settings and user-defined settings allowing dynamic sore and retrieve property settings for information which is required to persist between running an application. My.Settings is also a bridge for developers who are used to using ini files where My.Settings is easy to understand a more robust than using .ini files.
Basic example
A simple example for remembering information using My.Settings: In this case, the information to remember is a color selection of a ColorDialog component.
- Create a new Visual Basic project.
- In Solution Explorer select the newly created project following by double-clicking on the "My Project" node which brings up the property pages.
- Select the Settings tab where there will be a grid which looks like a DataGridView ready to add a new row.
- Single click on the first row, the first cell and enter SelectedColor.
- Select the combo box in the second cell, using the dropdown select System.Drawing.Color.
- Press CTRL+S to commit the new property.
- Select the form canvas for Form1, from the toolbox double click on a ColorDialog.
- Create a form load event and place the code shown in the first code block below.
- Place a single button on the form followed by double-clicking the button to create a click event.
Form load code. Determine if SelectedColor has been set via IsEmpty property, if not set the color to the ColorDialog.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If Not My.Settings.SelectedColor.IsEmpty Then
ColorDialog1.Color = My.Settings.SelectedColor
End If
End Sub
Click event code for above where if the user selects a color and presses OK the color is remembered and used as per the load event above.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If ColorDialog1.ShowDialog() = DialogResult.OK Then
My.Settings.SelectedColor = ColorDialog1.Color
End If
End Sub
In the example above, until the user selects a color nothing is stored while after a selection is made (in this case) which when saved is stored under AppData folder which will be discussed later on how to find this folder and configuration file.
Another example with less code, in this case, remembers the first name.
- Create a new project.
- Add a TextBox to the form.
- Select properties
- Select (ApplicationSettings) -> (PropertyBinding)
- Press the button, a dialog appears, select Text.
- Click the drop-down, single click the dropdown, single click the new link.
- Use FirstName for the Name.
- Press enter twice.
- Run the project.
- Enter your name in the TextBox.
- Close the application using the system close button in the title bar of the form.
- Run the project again to see your name appear.
In the above example, there is zero code e.g.
Public Class Form1
End Class
Visual Studio has generated the necessary code under Settings.settings which can be viewed by selecting from the project menu, show all files.
<Global.System.Configuration.UserScopedSettingAttribute(), _
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
Global.System.Configuration.DefaultSettingValueAttribute("")> _
Public Property FirstName() As String
Get
Return CType(Me("FirstName"),String)
End Get
Set
Me("FirstName") = value
End Set
End Property
While at the same time Visual Studio generated the following code in Form1.Designer.vb to persist changes.
'
'TextBox1
'
Me.TextBox1.DataBindings.Add(
New System.Windows.Forms.Binding("Text",
Global.Basic.My.MySettings.Default, "FirstName", True,
System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged))
Saving property values
By default under project settings on the Application tab, there is a checkbox checked "Save My.Settings on ShutDown", unchecking this means the developer must manually save changes e.g. My.Settings.Save().
Remembering user details
When an application does not use a database and information needs to be remembered this is another good example for storing information under My.Settings.
User configuration file location
When setting are saved in production they are placed under C:\Users\profile name\AppData\Local\Microsoft with a folder name as
Example1.exe_Url_3uftystdm0jwkfffml5uukwrycaww04i
Where Example1.exe is the project name followed by an underscore and a generated folder name unique to the application. Beneath this folder are one or more folders with the version number of the application. When a new version of the application is released call My.Settings.Upgrade (see details for Upgrade).
To learn the location of this folder add a reference to System.Configuration to your project.
Get the folder
Public Function GetConfigurationFolder() As String
Dim config = ConfigurationManager.
OpenExeConfiguration(ConfigurationUserLevel.
PerUserRoamingAndLocal)
Return config.FilePath.Replace("\user.config", "")
End Function
Get the configuration file name
Public Function ConfigurationFile() As String
Return Path.GetFileName(ConfigurationManager.
OpenExeConfiguration(ConfigurationUserLevel.
PerUserRoamingAndLocal).FilePath)
End Function
Settings change notification
This section will explain how to watch for properties changed for My.Settings using SettingChanging event of My.Settings. To monitor changes in a code module clear all generated code and add the following.
Namespace My
End Namespace
The following class must reside in the My namespace which in this case has one event for monitoring changes on a setting named BackUpDate setup as DateTime. If a Date is set prior to the current day a message box appears indicating a future date is required followed by rejecting/cancelling the proposed new value.
Namespace My
Partial Friend NotInheritable Class MySettings
Inherits ApplicationSettingsBase
Private Sub MySettings_SettingChanging(sender As Object,
ByVal e As System.Configuration.SettingChangingEventArgs) Handles Me.SettingChanging
If (e.SettingName.Equals("BackupDate")) Then
Dim newBackupDate = CType(e.NewValue, Date)
If newBackupDate < Now Then
MessageBox.Show(
$"{newBackupDate.ToShortDateString()} is before today, date must be after today")
e.Cancel = True
End If
End If
End Sub
End Class
End Namespace
Test code for monitoring changes for BackupDate setting.
Private Sub Button1_Click(sender As Object, e As EventArgs) _
Handles Button1.Click
Console.WriteLine($"Before change: {My.Settings.BackupDate}")
My.Settings.BackupDate = Now.AddDays(-2)
Console.WriteLine($"After change: {My.Settings.BackupDate}, still the same")
Console.WriteLine($"Before change: {My.Settings.BackupDate}")
My.Settings.BackupDate = Now.AddDays(2)
Console.WriteLine($"After change: {My.Settings.BackupDate}, new date has been set")
End Sub
Results
Before change: 12/21/2018 6:10:47 AM
After change: 12/21/2018 6:10:47 AM, still the same
Before change: 12/21/2018 6:10:47 AM
After change: 12/25/2018 6:13:39 AM, new date has been set
My.Settings customization
Besides creating properties under project properties tab a developer can create a partial class for MySettings class under the My namespace. The following custom class provides properties to remember information for connection strings in the user configuration file along with properties which can be shared across projects and a few properties for locating the user configuration file. Note that there are duplicate properties for server and default catalog, this is to demonstrate two ways to work with properties.
Viewing properties and functions can be done using a PropertyGrid. The following screenshot represents data from the class above.
The custom class for setting and getting settings for the above settings.
- Properties with Category and DescriptionAttribute are for when there is a need to display properties in a PropertyGrid otherwise these are not needed.
- Properties marked Browsable(False) means the property will not be displayed in a PropertyGrid.
- Category indications the section to display the item in the PropertyGrid.
- Grey out properties which are read-only properties.
Imports System.ComponentModel
Imports System.Configuration
Imports System.IO
Namespace My
Partial Class MySettings
''' <summary>
''' User configuration folder path on the current computer.
''' </summary>
''' <returns>The current user's user configuration folder path</returns>
<Category("Local"), Browsable(True),
DescriptionAttribute("User configuration folder path")>
Public ReadOnly Property ConfigurationFolder() As String
Get
Dim config = ConfigurationManager.
OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal)
Return config.FilePath.Replace("\user.config", "")
End Get
End Property
''' <summary>
''' Determines if the current user's configuration folder exists
''' </summary>
''' <returns>True if folder exists, False if the folder does not exits</returns>
<Category("Local"), Browsable(True),
DescriptionAttribute("User configuration folder exists")>
Public ReadOnly Property ConfigurationFolderExists() As Boolean
Get
Return Directory.Exists(ConfigurationFolder)
End Get
End Property
''' <summary>
''' Provides name of current user's configuration file name
''' </summary>
''' <returns></returns>
<Category("Local"), Browsable(True),
DescriptionAttribute("User configuration file name")>
Public Function ConfigurationFile() As String
Return Path.GetFileName(ConfigurationManager.
OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath)
End Function
''' <summary>
''' Get shared folder
''' </summary>
''' <returns>Shared folder path</returns>
<Category("Local"), Browsable(True),
DescriptionAttribute("Folder where common settings are stored")>
Public ReadOnly Property SharedFolder() As String
Get
Return Path.Combine(Environment.
GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MyData")
End Get
End Property
<Category("Local"), Browsable(True),
DescriptionAttribute("Indicates common settings folder exists")>
Public ReadOnly Property SharedFolderExists() As Boolean
Get
Return Directory.Exists(SharedFolder)
End Get
End Property
<Category("Local"), Browsable(True),
DescriptionAttribute("Indicates common file name")>
Public ReadOnly Property CommonConfigurationFileName() As String
Get
Return Path.Combine(SharedFolder, "common.xml")
End Get
End Property
<Category("Local"), Browsable(True),
DescriptionAttribute("Indicates common settings file exists")>
Public ReadOnly Property CommonFigurationFileExists() As Boolean
Get
Return File.Exists(CommonConfigurationFileName)
End Get
End Property
Private _fileMap As ConfigurationFileMap
Private _configuration As Configuration
Private _fileName As String
''' <summary>
''' Get shared server name
''' </summary>
''' <returns>shared server name from common configuration file</returns>
<Category("Shared"), Browsable(False)>
Public ReadOnly Property GetServerName() As String
Get
Return _configuration.AppSettings.Settings("ServerName").Value
End Get
End Property
''' <summary>
''' Set shared server name to common configuration file
''' </summary>
''' <param name="pValue">Server name</param>
<Category("Shared"), Browsable(False)>
Public Sub SetServerName(pValue As String)
_configuration.AppSettings.Settings("ServerName").Value = pValue
_configuration.Save()
End Sub
<Category("Shared"), Browsable(True),
DescriptionAttribute("Default server")>
Public Property ServerInGrid() As String
Get
Return _configuration.AppSettings.Settings("ServerName").Value
End Get
Set
_configuration.AppSettings.Settings("ServerName").Value = Value
_configuration.Save()
End Set
End Property
<Category("Shared"), Browsable(True),
DescriptionAttribute("Default server")>
Public Property DatabaseInGrid() As String
Get
Return _configuration.AppSettings.Settings("DefaultCatalog").Value
End Get
Set
_configuration.AppSettings.Settings("DefaultCatalog").Value = Value
_configuration.Save()
End Set
End Property
''' <summary>
''' Get default catalog
''' </summary>
''' <returns>Default catalog from common configuration file</returns>
<Category("Shared"), Browsable(False)>
Public ReadOnly Property GetDefaultCatalog() As String
Get
Return _configuration.AppSettings.Settings("DefaultCatalog").Value
End Get
End Property
<Category("Shared"), Browsable(True),
DescriptionAttribute("Default database")>
Public ReadOnly Property Database() As String
Get
Return GetDefaultCatalog()
End Get
End Property
<Category("Shared"), Browsable(True),
DescriptionAttribute("Default server")>
Public ReadOnly Property Server() As String
Get
Return GetServerName()
End Get
End Property
''' <summary>
''' Set default catalog to common configuration file
''' </summary>
''' <param name="pValue">Server name</param>
<Category("Shared"), Browsable(True)>
Public Sub SetDefaultCatalog(pValue As String)
_configuration.AppSettings.Settings("DefaultCatalog").Value = pValue
_configuration.Save()
End Sub
Public Sub New()
_fileName = CommonConfigurationFileName
_fileMap = New ConfigurationFileMap(_fileName)
_configuration = ConfigurationManager.OpenMappedMachineConfiguration(_fileMap)
End Sub
End Class
End Namespace
Properties with Shared in the name refer to an XML file stored under C:\ProgramData\MyData in common.xml. There is no code to create the folder instead the folder would be created either in an installation of the application or directly in the application.
Common.xml
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="appSettings"
type="System.Configuration.AppSettingsSection,
System.Configuration, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
/>
</configSections>
<appSettings>
<add key="ServerName" value="KARENS-PC" />
<add key="DefaultCatalog" value="NorthWindAzure" />
</appSettings>
</configuration>
- ServerName, in this case, would refer to a SQL-Server instance name which may be .\SQLEXPRESS.
- DefaultCatalog refers to the default database to work with on ServerName when needing to read, write or remove data.
Summary
In this article, a developer has the ability to work efficiently with an alternative to using .ini files, persist settings of an application between sessions plus how to validate settings with provides code to reject changes.
See also
Secure connection string for Windows Forms
Database selective connection strings
Source code
Source code is at the following GitHub repository.