KnowDotNet NetRefactor

Compact Framework - Use XML Files to Replace The Registry

GetSetting and SaveSetting Registry Settings Replacement

by Les Smith
Print this Article Discuss in Forums

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.

Testing Form


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


Figure 3 - VB.NET Code for CSettings Class.

The following code is C# event handlers for setting up and calling the class.

    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);
    }

This code is the C# code for CSettings.

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


Top of Page

Figure 4 - C# Code for CSetting 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