다음을 통해 공유


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.

  1. Create a new Visual Basic project.
  2. In Solution Explorer select the newly created project following by double-clicking on the "My Project" node which brings up the property pages.
  3. Select the Settings tab where there will be a grid which looks like a DataGridView ready to add a new row.
  4. Single click on the first row, the first cell and enter SelectedColor.
  5. Select the combo box in the second cell, using the dropdown select System.Drawing.Color.
  6. Press CTRL+S to commit the new property.
  7. Select the form canvas for Form1, from the toolbox double click on a ColorDialog.
  8. Create a form load event and place the code shown in the first code block below.
  9. 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.

  1. Create a new project.
  2. Add a TextBox to the form.
  3. Select properties
  4. Select (ApplicationSettings) -> (PropertyBinding)
  5. Press the button, a dialog appears, select Text.
  6. Click the drop-down, single click the dropdown, single click the new link.
  7. Use FirstName for the Name.
  8. Press enter twice.
  9. Run the project.
  10. Enter your name in the TextBox.
  11. Close the application using the system close button in the title bar of the form.
  12. 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.

Under project properties

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.