Einstellungen einer Windows Anwendung speichern unter .NET 2.0

Die ersten Erfahrungen mit dem .NET Framework 2.0 waren sehr erfreulich. Als eines der ersten Features habe ich mir die "Anwendungseinstellungen" vorgenommen und war total begeistert. Endlich wird einem diese lästige Aufgabe komplett abgenommen auch das Binden von Einstellunge auf Eigenschaften eines Controls finde ich super! Nur noch ein Load() und Save() in den Code einbauen und fertig. So dachte ich zumindest aber der Frust kam relativ schnell:

Das Speichern von benutzerabhängigen Einstellungen wird unter c:\Dokumente und Einstellungen\benutzername\.... vorgenommen. So weit kein Problem nur das die Versionsnummer mit im Pfad stehen muss finde ich richtig übel. So bald sich die Versionnummer ändert ist es mit den alten Einstellungen essig ... es gibt zwar eine Upgrade() Methode aber bei der Verwendung von SettingKey funktioniert das nicht mehr :(

Also habe ich versucht den Pfad anzupassen und habe gegoogelt .. siehe da: Es geht nicht .... super gemacht, toll durchdacht aber dann trotzdem leider auf den letzten Metern versaut. Immerhin hat man die Möglichkeit einen eigenenen Provider zu schreiben, um die Einstellungen abzuspeichern. Das wiederum ist klasse gelöst und mehr als sinnvoll!

Nun hier ist eine Provider, der die Einstellungen im XML-Format unter dem Anwendungsverzeichnis speichert:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.Windows.Forms;
using System.Xml;
using System.Collections.Specialized;
using Microsoft.Win32;


namespace GaliNeo.Framework.GaliNeoSettings
{
class GaliNeoSettingsProvider : SettingsProvider
{
XmlDocument doc = null;
XmlNode root = null;
XmlNode userSettings = null;
XmlNode appSettings = null;

public GaliNeoSettingsProvider()
{
doc = new XmlDocument();
LoadSettings();
}

public override string ApplicationName
{
get { return Application.ProductName; }
set { }
}

public override void Initialize(string name, NameValueCollection col)
{
base.Initialize(this.ApplicationName, col);
}


public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals)
{

foreach (SettingsPropertyValue propval in propvals)
{

SettingsProperty prop = propval.Property;

setValue(prop, propval, context);

}

this.WriteSettings();
}

public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection props)
{

// Create new collection of values
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
string sectionName = this.GetSectionName(context);
string settingKey = (string)context["SettingsKey"];


// Iterate through the settings to be retrieved
foreach (SettingsProperty setting in props)
{
SettingsPropertyValue value = new SettingsPropertyValue(setting);
value.IsDirty = false;
value.SerializedValue = getValue(setting, context );

values.Add(value);
}
return values;

}


private XmlNode SerializeToXmlElement(SettingsProperty setting, SettingsPropertyValue value)
{

XmlElement element = doc.CreateElement("value");
string text1 = value.SerializedValue as string;
if ((text1 == null) && (setting.SerializeAs == SettingsSerializeAs.Binary))
{
byte[] buffer1 = value.SerializedValue as byte[];
if (buffer1 != null)
{
text1 = Convert.ToBase64String(buffer1);
}
}
if (text1 == null)
{
text1 = string.Empty;
}
if (setting.SerializeAs == SettingsSerializeAs.String)
{
//text1 = this.Escaper.Escape(text1);
}

element.InnerXml = text1;
XmlNode node1 = null;
foreach (XmlNode node2 in element.ChildNodes)
{
if (node2.NodeType == XmlNodeType.XmlDeclaration)
{
node1 = node2;
break;
}
}
if (node1 != null)
{
element.RemoveChild(node1);
}
return element;
}

private string GetSectionName(SettingsContext context)
{
string groupName = (string)context["GroupName"];
string settingKey = (string)context["SettingsKey"];
string section = groupName;
if (!string.IsNullOrEmpty(settingKey))
{
object[] arrName = new object[] { section, settingKey };
section = string.Format("{0}.{1}", arrName);
}
return XmlConvert.EncodeLocalName(section);
}


#region DAN


private string getXPathQueryProperty(SettingsProperty setting, SettingsContext context)
{
string xPathQuery = getXPathQuerySection(setting, context);

if (setting.Name != "")
{
xPathQuery += "/" + setting.Name;
} //if (propName != "")

return xPathQuery;
}

private string getXPathQuerySection(SettingsProperty setting, SettingsContext context)
{
string xPathQueryGroup = doc.DocumentElement.LocalName ;

if (this.IsUserScoped(setting))
{
xPathQueryGroup += "/userSettings";
}
else
{
xPathQueryGroup += "/appSettings";
}
xPathQueryGroup += "/" + GetSectionName(context);


return xPathQueryGroup;

}



private void CreatePropNode(SettingsProperty setting, SettingsPropertyValue value, SettingsContext context)
{
string xPathQuery = getXPathQuerySection(setting, context);

XmlNode groupNode = doc.SelectSingleNode(xPathQuery);

if (groupNode == null)
{
groupNode = doc.CreateElement(GetSectionName(context));

if (this.IsUserScoped(setting))
{
userSettings.AppendChild(groupNode);
}
else
{
appSettings.AppendChild(groupNode);
}

} //if (node == null)


XmlNode nodeProp = doc.CreateElement(setting.Name);

nodeProp.AppendChild (this.SerializeToXmlElement(setting,value) );

groupNode.AppendChild(nodeProp);

}

private void setValue(SettingsProperty setting, SettingsPropertyValue value, SettingsContext context) //string propName, string groupName, object value, object defaultvalue)
{

string xPathQuery = getXPathQueryProperty(setting,context);

XmlNode node = doc.SelectSingleNode(xPathQuery);
if (node != null)
{
XmlNode valueNode = SerializeToXmlElement(setting, value);
node.RemoveAll();
node.AppendChild(valueNode);
}
else
{

CreatePropNode(setting, value, context);

} //if (node != null)

}

private object getValue(SettingsProperty setting, SettingsContext context)
{
string xPathQuery = getXPathQueryProperty(setting, context);

XmlNode node = doc.SelectSingleNode(xPathQuery + "/value");

if (node != null)
{
return node.InnerXml;
}
else if (setting.DefaultValue != null)
{
return setting.DefaultValue;
}
else
{
return null;
}

}

// Helper method: walks the "attribute bag" for a given property
// to determine if it is user-scoped or not.
// Note that this provider does not enforce other rules, such as
// - unknown attributes
// - improper attribute combinations (e.g. both user and app - this implementation
// would say true for user-scoped regardless of existence of app-scoped)
private bool IsUserScoped(SettingsProperty prop)
{
foreach (DictionaryEntry d in prop.Attributes)
{
Attribute a = (Attribute)d.Value;
if (a.GetType() == typeof(UserScopedSettingAttribute))
return true;
}
return false;
}

#endregion

private void LoadSettings()
{
string configFile = getPath() + "user.config";

if (System.IO.File.Exists(configFile) )
{
doc.Load(configFile);
root = doc.DocumentElement;
userSettings = doc.DocumentElement.SelectSingleNode("./userSettings");
appSettings = doc.DocumentElement.SelectSingleNode("./appSettings"); ;

}
else
{

try
{
root = doc.CreateElement("configuration");

userSettings = doc.CreateElement("userSettings");
root.AppendChild(userSettings);
appSettings = doc.CreateElement("appSettings");
root.AppendChild(appSettings);

doc.AppendChild(root);
}
catch
{

}
}

}

private string getPath()
{
return Application.StartupPath + @"\App_Data\" ;
}


private void WriteSettings()
{
if (!( System.IO.Directory.Exists(getPath())))
{
System.IO.Directory.CreateDirectory(getPath());
}
string configFile = getPath() + "user.config";


doc.Save(configFile);


}

}
}

Nun das ist noch nicht 100% best practice Entwicklung (musste schnell gehen) aber es funktioniert ....:)

 

 

Kommentare (2) -

MrKeineAhnung
06.04.2006 14:12:50 #

Hallo,

ich habe versucht Deinen Code zu implementieren. Dabei bleibt VS2005 immer mit einer Fehlermeldung in der Zeile

namespace GaliNeo.Framework.GaliNeoSettings

stehen :

Error  1  The type 'System.Configuration.Provider.ProviderBase' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.  ...\GaliNeoSettings.cs

Was machte ich da falsch ?

Gruß
Axel

PS: Der Source sieht sonst super und äußerst kompent aus ... soweit ich ihn überhaupt verstehe Wink

Daniel
08.04.2006 15:27:16 #

Hallo,

Sorry, habe Deinen Kommentar erst jetzt gesehen... Du hast vermutlich vergessen einen Verweis von "System.configuration.dll" in Dein Projekt mit aufzunehmen. Dann sollte es ohne Probleme funktionieren.

Wenn nicht, dann melde Dich doch einfach noch mal...

Grüße
Daniel

Kommentar schreiben