When the AppSettings instance is created, the private "init" method is called. This checks if the "Settings" directory is there and creates it if it isn't. Then, it loads the settings.
///
/// Initializes the settings path and creates the "Settings" directory if it doesn't exist.
///
private void init()
{
_fFirstTimeLoad = false;
_strSettingsPath = Path.Combine(Environment.CurrentDirectory, SettingsDirectory);
if (!Directory.Exists(_strSettingsPath) )
{
_fFirstTimeLoad = true;
Directory.CreateDirectory(_strSettingsPath);
}
// Or if there's no files in the settings directory, treat it like a first time run
if (Directory.GetFiles(_strSettingsPath).Length == 0)
{
_fFirstTimeLoad = true;
}
loadSettings();
}
The loadSettings() method just calls the static "load" method on each of the components of the settings.
private void loadSettings()
{
_globalSettings = GlobalSettings.load(_strSettingsPath);
_networkSettings = NetworkSettings.load(_strSettingsPath);
_lanSettings = LanSettings.load(_strSettingsPath);
_otherSettings = OtherSettings.load(_strSettingsPath);
}
Each of the settings classes derive from a base class that handles the XML serialization to and from disk.
In a nutshell it opens a FileStream, creates a serializer of the correct type and then calls Deserialize. Viola! Your settings are restored! Here's the guts of it. I removed the exception handling code just to keep it brief here.
protected static AbstractSettingsItem read(Type type, string strPath)
{
FileStream fs;
fs = File.Open(strPath, FileMode.Open, FileAccess.Read);
XmlSerializer xs = new XmlSerializer(type);
object objData;
objData = xs.Deserialize(fs);
fs.Close();
return (objData as AbstractSettingsItem);
}
The code to save the settings is very similar except, "Serialize" is called instead. This makes for a very easy way to blast settings to disk and restore them later. Provided all settings are initialized with proper defaults, adding new settings are accommodated easily as the program grows. I don't know if this is the best way of doing this, but it seems to work pretty well.
I think one way to improve it would be to extract an interface to pass to and from the subclasses and the base class, so that reading doesn't pass back an object of type "AbstractSettingsItem" - it just seems awkward to me. Not sure what methods would be defined in the interface, though. I'll have to think about that more.
For now, if I want to add a new settings class, I just derive from "AbstractSettings", add the data members to hold the settings data, and write the properties that are to be saved and restored between sessions. Then add an instance to the AppSettings class and add the calls to "load" and "save".
I realized as I was writing this, that the current implementation is pretty much limited to simple types: boo, int, string, etc. The default XML serialization handles arrays and collections pretty well, and also nested objects, as long as they have public read and write properties. Beyond that, I think I'd have to provide a custom serializer or handle writing out my own XML document. For the most part, I think settings fall into the "simple types" category. At least I haven't run into anything that required something more complex.
Next up, saving and restoring the main window size and state with a system tray icon.
No comments:
Post a Comment