If your Compact Framework application has to save settings, you may want to go through the hassle of writing to the system Registry. When it comes to developing on the Compact Framework, accessing the Registry is just not worth the trouble if you can find a way around it. The VB GetSetting and SaveSetting functions are not available. If you are developing in C#, you never had those functions anyway; but using APIs is no fun, not to me at least. Why not use an XML file to save your settings?
This class provides overloaded methods of VBs GetSetting and SaveSetting functionality. I have written it so that no program changes have to be made, other than to instantiate an instance of the class and place the object instance name in front of all GetSetting and SaveSetting function calls. Actually, the class could have been written as a module (C# programmers, pretend I didn't use the word Module), and then it would not have to be instantiated. However, I wrote it as a class for several reasons. I program in both VB.NET and CSharp, so I am attempting to consider both languages as I write new code. C# does not support modules; rather it provides Shared Classes. You can do the same thing in VB.NET by making all methods and variables Shared. But, then I would have to place the name of the class as a prefix to all references to GetSetting or SaveSetting, just as if I were instantiating it as an object.
As you examine the code for the class, you will see that the SaveSetting and GetSetting methods support the calls exactly as if the user were using the built-in VB.NET functions. That was on purpose so the user does not have to change the respective calls. You will note that the constructor accepts a Boolean name "AllUsers". For this Compact Framework (CF) application, I do not support multiple user functionality, so the boolean is passed as True to instantiate the object. If this Boolean is True, an XML file will be named just using the passed AppTitle string. However, if the Boolean is False, the class will append the UserName from the Environment as part of the XML filename (not supported on CF), thus allowing multiple users to share a computer and your application, while maintaining their own settings. Finally, there is a Public property called "AlternatePath", which allows the user to supply the path where they want the settings saved.
Although I have only used one "Settings" paramater value in this application, the class will support any number of Settings, such as Settings, Registration, etc. The XML file will support a hierarchy of multiple key values within multiple settings.
Initially, your application will not have any XML setting file, so the class will return the default values that your application passes when calling GetSetting.
I have only provided three Overloaded metods for each of the respective functions, because Integer, String, and Boolean will normally cover most application settings. If you need another type of setting, simply add a pair of overloads for the needed type.
Figure 3 shows the VB.NET code for the class. I know that C# programmers don't normally have access to GetSetting and SaveSetting (which from a VB programmers perspective, are great functions), so I have taken the time to convert the class to C# Code. I hope it might be used by a C# programmer. You can get both the VB.NET and C# applications by download the code for this article.
The class is straight-forward, nothing fancy, so I won't bore you with further verbage on how it works. The form shown in Figure 1 was designed to test the class in VB.NET. Figure 2 shows the code behind the form. This code sets up the object and the button event handlers call GetSetting and SaveSetting to read and write the XML file.
Figure 1 - Test Form for CSettings.VB.
Figure 2 - Form1 Code for Calling CSetting Object.
| Private oSettings As CSettings Const AppTitle = "TestSettings" Const Settings = "Settings" Const TextTest = "TEXTSETTING" Const CkTest = "CKSETTING" Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load ' for the cf, allusers must be true oSettings = New CSettings(True) End Sub Private Sub btnSaveSettings_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnSaveSettings.Click With oSettings .SaveSetting(AppTitle, Settings, TextTest, MetxtTestTextSetting.Text) .SaveSetting(AppTitle, Settings, CkTest, MeCheckBox1.Checked) End With End Sub Private Sub btnGetSettings_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnGetSettings.Click With oSettings Me.txtTestTextSetting.Text = .GetSetting(AppTitle, _ Settings, TextTest, "Not Set") Me.CheckBox1.Checked = .GetSetting(AppTitle, Settings, CkTest, False) End With End Sub Private Sub btnClearSettings_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnClearSettings.Click With Me .txtTestTextSetting.Text = String.Empty .CheckBox1.Checked = False End With End Sub |
| private CSharp2003WindowsApplication1.CSettings oSettings; const string AppTitle = "TestSettings"; const string Settings = "Settings"; const string TextTest = "TEXTSETTING"; const string CkTest = "CKSETTING"; public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); // // TODO: Add any constructor code after InitializeComponent call // // for the cf, allusers must be true; oSettings = new CSharp2003WindowsApplication1.CSettings(true); } private void btnClearSettings_Click(object sender, System.EventArgs e) { this.txtTestTextSetting.Text = String.Empty; this.CheckBox1.Checked = false; } private void btnGetSettings_Click(object sender, System.EventArgs e) { this.txtTestTextSetting.Text = oSettings.GetSetting(AppTitle, Settings, TextTest, "Not Set"); this.CheckBox1.Checked = oSettings.GetSetting(AppTitle, Settings, CkTest, false); } private void btnSaveSettings_Click(object sender, System.EventArgs e) { oSettings.SaveSetting(AppTitle, Settings, TextTest, thistxtTestTextSetting.Text); oSettings.SaveSetting(AppTitle, Settings, CkTest, thisCheckBox1.Checked); } |
| Option Strict On Imports System Public Class CSettings #Region " Class Variables " Private ds As DataSet Private xmlFile As String = String.Empty Dim _AllUsers As Boolean Const XML As String = ".xml" Private _AlternatePath As String = String.Empty #End Region #Region " Public SaveSetting Overloaded Methods " Public Overloads Sub SaveSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal Key As String, _ ByVal Value As Boolean) SaveSetting(AppTitle, Settings, Key, CStr(Value)) End Sub Public Overloads Sub SaveSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal Key As String, _ ByVal Value As Integer) SaveSetting(AppTitle, Settings, Key, CStr(Value)) End Sub Public Overloads Sub SaveSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal Key As String, _ ByVal Value As String) ' this method sets or adds the value row for the passed key Try If xmlFile.Length = 0 Then SetupXMLFileName(AppTitle) If ds Is Nothing Then ds = New DataSet Dim dt As DataTable = CreateDT(Settings, Key, Value) ds.Tables.Add(dt) Else Dim dt As DataTable = ds.Tables(Settings) If dt Is Nothing Then ' create new datatable named Settings dt = CreateDT(Settings, Key, Value) ds.Tables.Add(dt) Else Dim i As Integer Dim b As Boolean For i = 0 To dt.Rows.Count - 1 If CStr(dt.Rows(i).Item("key")) = Key Then dt.Rows(i).Item("value") = Value b = True Exit For End If Next If Not b Then AddRow(dt, Key, Value) End If End If End If ds.WriteXml(xmlFile) Catch ex As System.Exception StructuredErrorHandler(ex) End Try End Sub #End Region #Region " Public Overloaded GetSetting Methods " Public Overloads Function GetSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal key As String, _ ByVal keyvalue As Integer) _ As Integer Dim o As Object = GetSetting(AppTitle, Settings, key, CStr(keyvalue)) If o Is Nothing Then Return keyvalue Else Return CType(o, Integer) End If End Function Public Overloads Function GetSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal key As String, _ ByVal keyvalue As Boolean) _ As Boolean Dim o As Object = GetSetting(AppTitle, Settings, key, CStr(keyvalue)) If o Is Nothing Then Return keyvalue Else Return CType(o, Boolean) End If End Function Public Overloads Function GetSetting(ByVal AppTitle As String, _ ByVal Settings As String, _ ByVal key As String, _ ByVal keyvalue As String) _ As Object Dim i As Integer Dim dr As DataRow Dim dt As DataTable Try If xmlFile.Length = 0 Then SetupXMLFileName(AppTitle) ' this method returns the value specified by the key If ds Is Nothing Then dt = GetXml(Settings) If dt Is Nothing Then Return keyvalue Else dt = ds.Tables(Settings) End If For i = 0 To dt.Rows.Count - 1 dr = dt.Rows(i) If CStr(dr("Key")) = key Then Return dr("Value") End If Next Return keyvalue Catch ex As System.Exception StructuredErrorHandler(ex) End Try End Function #End Region #Region " Private Methods " Private Function CreateDT(ByVal Settings As String, ByVal key As String, _ ByVal value As Object) As DataTable Dim dt As DataTable dt = New DataTable(Settings) dt.Columns.Add("Key", Type.GetType("System.String")) dt.Columns.Add("Value", Type.GetType("System.String")) AddRow(dt, key, value) Return dt End Function Private Sub AddRow(ByRef dt As DataTable, ByVal key As String, _ ByVal value As Object) Dim newRow As DataRow = dt.NewRow newRow(0) = key newRow(1) = value dt.Rows.Add(newRow) End Sub Private Function GetXml(ByVal tablename As String) As DataTable If Not IO.File.Exists(xmlFile) Then Return Nothing End If ds = New DataSet ds.ReadXml(xmlFile) Dim dt As DataTable = ds.Tables(tablename) Return dt End Function Private Sub SetupXMLFileName(ByVal fn As String) ' Returns filename for xmlfile, generated by using ' AppTitle suppliied to the two public methods and then ' boolean supplied to the constructor. ' install directory may be locked so check to see if ' caller supplied an alternate directory. Dim s As String If _AlternatePath.Length = 0 Then s = IO.Path.GetDirectoryName(Reflection.Assembly. _ GetExecutingAssembly.GetModules(0).FullyQualifiedName) Else s = IO.Path.GetDirectoryName(_AlternatePath) End If ' compact framework does not support user logon, so ' we don't support multiple app files on the cf ' If _AllUsers Then xmlFile = s & "\" & fn & XML ' Else ' xmlFile = s & "\" & fn & "_" & Environ("UserName") & XML ' End If End Sub #End Region #Region " Constructor " Public Sub New(ByVal AllUsers As Boolean) Me._AllUsers = AllUsers End Sub #End Region #Region " Property Methods " Public Property AlternatePath() As String Get Return _AlternatePath End Get Set(ByVal Value As String) _AlternatePath = Value End Set End Property #End Region End Class |
using System; using System.Reflection; using System.Data; namespace CSharp2003WindowsApplication1 { /// <summary> /// Summary description for CSettings. /// public class CSettings { #region " Class Variables " private DataSet ds; private string xmlFile = String.Empty; private bool m_AllUsers; const string XML = ".xml"; private string m_AlternatePath = String.Empty; #endregion #region " SaveSetting Methods " public void SaveSetting(string AppTitle, string Settings, string Key, bool Value) { SaveSetting(AppTitle, Settings, Key, Value.ToString()); } public void SaveSetting(string AppTitle, string Settings, string Key, int Value) { SaveSetting(AppTitle, Settings, Key, Value.ToString()); } public void SaveSetting(string AppTitle, string Settings, string Key, string Value) { if (xmlFile.Length==0) SetupXMLFileName(AppTitle); if (ds == null) { ds = new DataSet(); DataTable dt = CreateDT(Settings,Key,Value); ds.Tables.Add(dt); } else { DataTable dt = ds.Tables[Settings]; if (dt == null) { // create new datatable dt = CreateDT(Settings,Key,Value); ds.Tables.Add(dt); } else { bool b=false; for (int i = 0; i < (int) dt.Rows.Count;i++) { if((string)dt.Rows[i].ItemArray[0] == Key) { dt.Rows[i].ItemArray[1] = Value; b = true; break; } } if (b != true) AddRow(ref dt, Key, Value); } } ds.WriteXml(xmlFile); } #endregion #region " GetSetting Methods " public int GetSetting(string AppTitle, string Settings, string Key, int KeyValue) { string o = GetSetting(AppTitle,Settings,Key,KeyValue.ToString().ToLower()); if (o == null) return KeyValue; else return int.Parse(o); } public bool GetSetting(string AppTitle, string Settings, string Key, bool KeyValue) { string o = GetSetting(AppTitle,Settings,Key,KeyValue.ToString().ToLower()); if (o == null) return KeyValue; else return bool.Parse(o); } public string GetSetting(string AppTitle, string Settings, string Key, string KeyValue) { DataRow dr; DataTable dt; if (xmlFile.Length == 0) SetupXMLFileName(AppTitle); if (ds == null) { dt = GetXml(Settings); if (dt == null) return KeyValue; } else dt = ds.Tables[Settings]; for (int i = 0; i < dt.Rows.Count; i++)<BR> { dr = dt.Rows[i]; if ((string) dr["Key"] == Key) return (string) dr["Value"]; } return KeyValue; } #endregion #region " Private Methods " private DataTable CreateDT(string Settings,string Key,string Value) { DataTable dt; dt = new DataTable(Settings); dt.Columns.Add("Key",Type.GetType("System.String")); dt.Columns.Add("Value",Type.GetType("System.String")); AddRow(ref dt,Key,Value); return dt; } private void AddRow(ref DataTable dt, string Key, object Value) { DataRow newRow = dt.NewRow(); newRow[0] = Key; newRow[1] = Value; dt.Rows.Add(newRow); } private DataTable GetXml(string tablename) { if (!System.IO.File.Exists(xmlFile)) return null; ds = new DataSet(); ds.ReadXml(xmlFile); DataTable dt = ds.Tables[tablename]; return dt; } /* Returns filename for xmlfile, generated by using AppTitle suppliied to the two public methods and then boolean supplied to the constructor. install directory may be locked so check to see if caller supplied an alternate directory. */ private void SetupXMLFileName(string fn) { string s; if (m_AlternatePath.Length == 0) s = System.IO.Path.GetDirectoryName(System.Reflection.Assembly. GetExecutingAssembly().GetModules()[0].FullyQualifiedName); else s = System.IO.Path.GetDirectoryName(m_AlternatePath); // compact framework not supported //if (m_AllUsers==true) xmlFile = s + "\\" + fn + XML; //else // xmlFile = s + "\\" + fn + "_" + Environment.UserName + XML; } #endregion #region " Constructor " public CSettings(bool AllUsers) { m_AllUsers = AllUsers; } #endregion #region " Public Properties " public bool AllUsers { get { return (bool) m_AllUsers; } set { bool |