|
|||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
ContentsIntroductionI was developing a small Windows app using C#, and I decided that it would be nice to save the window's position and size when the app exited so it would be the same the next time the app was run. Having come from the MFC world, I searched for something equivalent to All these similar mechanisms, each with their own interfaces... which one to use? I just needed a simple way to persist my window's position and size somewhere to be later retrieved. I set my small Windows app project on the side and decided that it was time to write a new class library; one that would unify all these mechanisms into a common and simple interface: the InterfaceSo what does this common interface look like? Here's a simplified version of it -- see IProfile.cs or AMS.Profile.chm for the complete definition: interface IProfile
{
void SetValue(string section, string entry, object value);
object GetValue(string section, string entry);
string GetValue(string section, string entry, string defaultValue);
int GetValue(string section, string entry, int defaultValue);
double GetValue(string section, string entry, double defaultValue);
bool GetValue(string section, string entry, bool defaultValue);
string[] GetEntryNames(string section);
string[] GetSectionNames ();
void RemoveEntry(string section, string entry);
void RemoveSection(string section);
bool ReadOnly
{
get;
set;
}
event ProfileChangingHandler Changing;
event ProfileChangedHandler Changed;
}
As you can see, it's a simple interface bearing a slight resemblance to the Aside from the standard Get and Set methods used to read and write the values, the interface also allows you to retrieve the names of the available entries and sections, and to remove them if desired. It even has a ClassesWhen it came time to implement the interface, I went with the most popular mediums available. XML was number one on the list. Its popularity is just impossible to ignore. The Registry was my second choice. Although people may be turning away from it, it's still a very efficient way to read and write data to a centralized location. Lastly, I went with INI files. I realize they're practically extinct these days but some people still use them due to their simplicity. Once I had completed my classes, I decided to add one more implementation to the list: one to handle config files. From the forums and articles here at CP, I noticed several developers needing a way to write to them. So I said, "Why not?". It's somewhat similar to the XML one so it didn't take long to write. The result was four classes, all part of the So how do these classes store their Profile data? Here's a brief synopsis of how each class works: XmlAs you probably know, XML is all about storing data inside a text file in pretty much any markup-based format. So which format would I choose to organize the data using the section/entry paradigm? After considering a couple of possibilities, I decided that the format below would be preferable, since it allows section and entry names to contain spaces. It also looks cleaner and more consistent than if I had used the section and entry names themselves to name the elements. <?xml version="1.0" encoding="utf-8"?>
<profile>
<section name="A Section">
<entry name="An Entry">Some Value</entry>
<entry name="Another Entry">Another Value</entry>
</section>
<section name="Another Section">
<entry name="This is cool">True</entry>
</section>
</profile>
Notice, the root element is called "profile". This is the default root name, which you may change via the class' RegistryFor the registry, I decided to default to the old familiar path, HKEY_CURRENT_USER\Software\Company\Product, with individual sections appearing as subkeys of that. Again, this path is customizable when creating the object, or later via the The above data would appear similar to this, when viewed on the Registry editor (regedit.exe): - My Computer
...
- HKEY_CURRENT_USER
...
- Software
...
- AMS
- ProfileDemo
- A Section Name Data
An Entry Some Value
Another Entry Another Value
- Another Section Name Data
This is cool True
IniINI files are pretty much self explanatory, format-wise. Here's the above data in INI format: [A Section]
An Entry=Some Value
Another Entry=Another Value
[Another Section]
This is cool=True
Like the XML file, the default file name will be based on the name and type of the application -- program.exe.ini or web.ini. If you don't like it, it's easy enough to change via the constructor or ConfigConfig files are the most complex of the bunch, format and code wise. Let me begin by illustrating how the above data would look: <configuration>
<configSections>
<sectionGroup name="profile">
<section name="A_Section"
type="System.Configuration.NameValueSectionHandler,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089, Custom=null" />
<section name="Another_Section"
type="System.Configuration.NameValueSectionHandler,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089, Custom=null" />
</sectionGroup>
</configSections>
<profile>
<A_Section>
<add key="An Entry" value="Some Value" />
<add key="Another Entry" value="Another Value" />
</A_Section>
<Another_Section>
<add key="This is cool" value="True" />
</Another_Section>
</profile>
<appSettings>
<add key="App Entry" value="App Value" />
</appSettings>
</configuration>
As you can see, there's a lot more going on here than with the other formats. The NameValueCollection section = (NameValueCollection)
ConfigurationSettings.GetConfig("profile/A_Section");
string value = section["An Entry"];
Notice, there's also an " string value = ConfigurationSettings.AppSettings["App Entry"];
Well, the Config config = new Config();
config.GroupName = null; // don't use the "profile" group
...
string value = config.GetValue("appSettings", "App Entry", null);
config.SetValue("appSettings", "Update Date", DateTime.Today);
One thing to keep in mind for Windows apps is that .NET caches the config data as it reads it, so any subsequent updates to it on the file will not be seen by the Like the UsageSo now that you've seen the classes, how do you go about using them in your code? Well, I packaged them inside their own DLL, called AMS.Profile.dll. This makes them easy to use in your various projects, without having to recompile them everywhere. Simply add the DLL to your project's References, which is done as follows inside Visual Studio .NET:
Which class should I use?OK, so how do you actually use these classes inside the code? That's the easy part, actually. The hard part may be deciding which one of the four to use. Whereas before you may have based your decision on the amount and complexity of the code involved, now that's no longer an issue. Now you just worry about which storage medium is best for the job. And that part is basically up to your program's requirements and/or personal preferences. Here are some of my observations to help you decide:
Still trying to decide? Here's the bottom line.
Even if you don't pick the proper class from the start, it's easy enough to switch to another one later. OOP rocks! How do I use the class?Now that you have selected the profile class for the job, how do you use them inside your code? Well, most of the time, you'll just declare the class as a field of another class and then call the Xml profile = new Xml();
...
int width = profile.GetValue("Main Window", "Width", 800);
int height = profile.GetValue("Main Window", "Height", 600);
...
profile.SetValue("Main Window", "Width", this.Size.Width);
profile.SetValue("Main Window", "Height", this.Size.Height);
Keep in mind that the Xml profile = new Xml();
...
using (profile.Buffer())
{
profile.SetValue("Main Window", "Width", this.Size.Width);
profile.SetValue("Main Window", "Height", this.Size.Height);
}
As you saw from the DemoI wrote the demo program to illustrate the functionality of the four Profile classes, and at the same time, to test the classes. I added a Test button that calls a method of the Keep in mind that this is just a demo program, not a utility. Each Profile object works with their default names. For example, for the To use the demo, select a Profile from the top combo box. This will cause the sections in the profile to be placed into the Section combo. Choose a section from there and you'll see all of its entries get added to the Entry combo box. Choose an entry from there and you'll see its value placed into the Value textbox. If you want to add a new Section or Entry, simply type it into the proper combo box. Press the Save button to write the value to the profile via History
| ||||||||||||||||||||||||||||