Storing external data for my program
Storing external data for my program
Storing external data for my program
Storing external data for my program
Storing external data for my program
Storing external data for my program Storing external data for my program Storing external data for my program Storing external data for my program Storing external data for my program Storing external data for my program Storing external data for my program Storing external data for my program
Storing external data for my program Storing external data for my program
Storing external data for my program
Go Back  Xtreme Visual Basic Talk > > > Storing external data for my program


Reply
 
Thread Tools Display Modes
  #1  
Old 09-12-2008, 07:19 AM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default Storing external data for my program


I'm rewriting a legacy application in .NET.

In the earlier version, I used a few control .INI files that could be edited by the advanced user to provide variation in certain program options. (The program also permitted override of these same variabes via menus and such.) I used the API functions to read the .INI files and rewrite them to alter the user's environment for subsequent runs.

Is this still reasonable, or is there a better way?
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.
Reply With Quote
  #2  
Old 09-12-2008, 08:37 AM
AtmaWeapon's Avatar
AtmaWeaponStoring external data for my program AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

It depends.

"The .NET way" dictates that you should use XML files in one of the four or five Application Data directories for user settings. .NET has tons of XML parsing functionality, and the recommended directories are always accessible to the users unless security is ridiculously paranoid.

You can still use P/Invoke to call the API functions to work with .INI files. The only problem you might encounter is the fact that I believe .INI files live in the program directory, which is usually a subdirectory of C:\Program Files. In default Vista limited user security and the recommended security environment on other platforms, users do not have write access to anything under this directory. If I'm wrong about INI files having to be here, I'd recommend tossing them in one of the user's Application Data directories.

To me, the right choice depends on two things. The first is how much inertia your users have: if they'll gnash their teeth and refuse to learn how the XML file works it's best to just stick with the INI files. The second is continuing support; MS has recommended against using INI files since at least the release of XP. Indeed, if you look at the GetPrivateProfileString documentation, you'll see this lovely tidbit:
Quote:
Note This function is provided only for compatibility with 16-bit Windows-based applications. Applications should store initialization information in the registry.
Technically, this means that at if at any time MS feels that 16-bit application compatibility is not important, this API function will disappear. Practically, this will probably never happen as many major applications still use INI files, but relying on deprecated functions is a loaded gun. Still, if your users are extremely hostile towards change, it's almost certain you'll be somewhere else before this happens so you may as well just keep using INI files. You might even want to look at the Nini project; I think they wrote a parser from the ground up so there are no dependencies on Windows API functions.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #3  
Old 09-12-2008, 12:42 PM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default

Actually, I used to have my Setup program store the Control.INI file in a subdirectory of my project, (which did go under C:\Program Files by default,) and it works okay . . . so far. And, it seems that most users could handle it when I told them to find this file and change, say, BackgroundColor = 15 to BackgroundColor = 1 if they didn't like the default.

I can see that XML may be the way to go, if that's what will be supported.

(I never went so far as to use the Registry. I'd hate to try talking a user through changing that.)


While on the subject: I had been reading in some initial constant and table data from external text files, but as those seemed vulnerable, I ended up using a resource file to build them into the program. Does .NET still support resource file functionality?
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.
Reply With Quote
  #4  
Old 09-24-2008, 12:24 AM
Roger_Wgnr's Avatar
Roger_Wgnr Roger_Wgnr is offline
CodeASaurus Hex

Forum Leader
* Expert *
 
Join Date: Jul 2006
Location: San Antonio TX
Posts: 2,427
Default

Quote:
Originally Posted by ElderKnight View Post
Does .NET still support resource file functionality?
Yes there is support for Resource files.
__________________
Code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. ~Martin Golding
The user is a peripheral that types when you issue a read request. ~Peter Williams
MSDN Visual Basic .NET General FAQ
Reply With Quote
  #5  
Old 10-14-2008, 01:16 PM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default

Quote:
Originally Posted by AtmaWeapon View Post
It depends.

"The .NET way" dictates that you should use XML files in one of the four or five Application Data directories for user settings. .NET has tons of XML parsing functionality, and the recommended directories are always accessible to the users unless security is ridiculously paranoid.

. . .
Gee, you'd think that amidst those tons of functionality, there's be a function to, let's say, look up and return the value of "NumberOfCycles" or "BackgroundColor" from an XML file.

Nope. I find that you have to read through the XML file one item at a time, checking levels as you go, and that it's slow enough that you need to post a message telling the user to go for a walk.

Given that I think it's friendlier to tell your user to edit ...

NumberOfCycles = 100

... than to search for and fix ...

<setting name="Number of Cycles" value="100" />

... I'm strongly tempted to keep the old .INI files. Even if support for the API's is dropped, they'll still be easier to handle within the program, and far faster.
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.
Reply With Quote
  #6  
Old 10-14-2008, 02:03 PM
Gruff's Avatar
GruffStoring external data for my program Gruff is offline
Bald Mountain Survivor

Retired Moderator
* Expert *
 
Join Date: Aug 2003
Location: Oregon, USA - deceased
Posts: 6,440
Default

Did you look at the project properties settings tab? You define them at design-time then edit them at run-time through my.settings object. Loading and Saving is automatic. This involves creating an options dialog as the interface but it is well worth it to avoid the config file issue (Assuming you do not have a *huge* config.)
It stores the settings in the App.Config file which is XML based.

I don't think that manually editing XML files by end users was part of the XML concept.

~T
__________________
Burn the land and boil the sea
You can't take the sky from me


~T

Last edited by Gruff; 10-14-2008 at 03:01 PM.
Reply With Quote
  #7  
Old 10-14-2008, 02:49 PM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default

I did see that. I'll try it if you think it might help matters.
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.
Reply With Quote
  #8  
Old 10-14-2008, 03:46 PM
AtmaWeapon's Avatar
AtmaWeaponStoring external data for my program AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

Quote:
Originally Posted by ElderKnight View Post
Gee, you'd think that amidst those tons of functionality, there's be a function to, let's say, look up and return the value of "NumberOfCycles" or "BackgroundColor" from an XML file.

Nope. I find that you have to read through the XML file one item at a time, checking levels as you go, and that it's slow enough that you need to post a message telling the user to go for a walk.
Wrong. Like so many before you, you've fallen into the trap of using the first thing you find in the documentation, then assuming if it's hard that .NET doesn't support what you want. Sometimes when you look for a solution you need to recognize you're at a dead end then backtrack to the start and try again.

Even so, I don't think direct parsing of a settings file is what you really want. Let's talk about it for the record, then I'll suggest using a settings file so .NET will do the bulk of the work for you.

There's two methods of XML parsing: SAX-style parsing and DOM-based parsing.

SAX-style parsing is akin to checking a text file line-by-line, but instead it moves from node to node of an XML file. It's messy, it's ugly, I hate it, but if you have a very large XML file it's very memory-efficient. This is what you are describing, and when I first started XML in .NET I latched on to it because DOM-based parsing looked "too hard". I was stupid then.

DOM-based parsing lets you make queries like these:
"Get me the value of any element with this name."
"Get me all elements with this name that are children of elements with this name."
"Get me the value of this attribute from elements named this that are children of elements with this attribute and value."

The upside is it's a lot easier to get specific values. The downside is you have to store the entire document in memory for it to work; if your document is large it's slow to load and uses a lot of memory.

Since it's just a configuration file I'm certain you won't hit the size barrier, so you might want to consider a DOM-based approach. I'm assuming you aren't using the .NET application settings file; honestly I don't use those and I don't have an explanation why; I am comfortable with writing my own configuration files. Let's start with a document:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<config>
    <UiOptions>
        <Size width="800" height="600" />
        <BackgroundColor value="#FF0000" />
    </UiOptions>
    <Operation>
        <Amplitude>10</Amplitude>
        <NumberOfCycles>100</NumberOfCycles>
    </Operation>
</config>
For simplicity, we'll say this is "config.xml" and it's in the same directory as the application.

Now, let's get the number of cycles taking a DOM-based approach:
Code:
    Private Function GetNumberOfCycles() As Integer
        Dim xDoc As New XmlDocument()
        xDoc.Load("config.xml")

        Dim nocNode As XmlNode = xDoc.SelectSingleNode("//NumberOfCycles")

        Return CInt(nocNode.InnerText)
    End Function
I asked for what I wanted, and I got it. It doesn't get easier than that!

"Aha, I've caught you, AtmaWeapon, what if I want to change the value?"

Oh, just change it then ask the program to save it:
Code:
    Private Sub SetNumberOfCycles(ByVal numberOfCycles As Integer)
        Dim xDoc As New XmlDocument()
        xDoc.Load("config.xml")

        Dim nocNode As XmlNode = xDoc.SelectSingleNode("//NumberOfCycles")
        nocNode.InnerText = numberOfCycles.ToString()

        xDoc.Save("config.xml")
    End Sub
This is enough drudgework that it's pretty much a given if you want to work with application settings you're going to serialize them to/from an object. Honestly, I'd want to do it if I were working with an INI file as well; in fact it's a good idea to have this object be the broker between your application and the configuration file so you can store the file in whatever format you want and let the rest of your code just worry about needing to call a method to write a configuration file.

This is where the built-in application settings stuff shines; it automatically generates a class that has a strongly-typed property for every setting. It lets you set default values so if the user deletes their settings you still have a sane value. It automatically saves itself in the appropriate application data folder.

In short, it helps you abstract the problem. What you want is "Get or set the value of this application setting, and save settings when I close." What you have to write if you do it yourself is, "Get the value of this node in this XML file. Set the value of this node in this XML file to this value, then save it."

I was going to go through the process of demonstrating using a class to abstract the storage medium away, but the settings file is so easy. Create a new console project. Open your project properties and go to the "settings" tab. Add "NumberOfCycles" and make it an integer. Now paste this into Module1 and run it a few times to observe the joys of using OOD to abstract your problems away:
Code:
Module Module1

    Sub Main()
        Dim numberOfCycles As Integer = My.Settings.NumberOfCycles

        Console.WriteLine("Current cycles: {0}", numberOfCycles)
        Dim newCyclesInput As String = GetUserInput("How many cycles?")
        Dim newCycles As Integer

        While Not Integer.TryParse(newCyclesInput, newCycles)
            newCyclesInput = GetUserInput("That's not a number.  How many cycles?")
        End While

        My.Settings.NumberOfCycles = newCycles
        My.Settings.Save()

        Console.WriteLine("Changed cycles to {0}.  Bye now!", My.Settings.NumberOfCycles)
    End Sub

    Private Function GetUserInput(ByVal prompt As String) As String
        Console.Write("{0} ", prompt)
        Dim input = Console.ReadLine()
        Return input
    End Function

End Module
You don't know it's XML. Your code doesn't know it's XML. It's stored in either local application data or application data based on how you scoped the variables (default is User, which means LocalSettings\Application Data\Application Name\Version). Microsoft might decide to revert to INI files and you won't have to change your code: the Settings class will simply change its implementation.

The only valid argument against this is that XML is a very heavy text format. Nothing's stopping you from making something similar to the Settings class to abstract away a custom text format

Now, hypocrite's corner: earlier I said I never use the .NET settings file and roll my own. Why is this? No one ever asked me a question about these and I'd never tried to use them. They didn't exist in .NET 1.1 (I think; I could be wrong) so I got in the habit of not using them early on. I can see some exotic scenarios where you'd want more control, but this should be fine for most cases.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #9  
Old 10-15-2008, 07:27 AM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default

My .INI files were extremely simple: one section, one value per key. Not so much a data base as a number of switches. No sub-levels. If I needed an array, I'd read it as a string and break it up afterward. Not only the MS Help, but everything I read online told you how to step through the file in great detail.

I'll give this another try. Thanks for the explanation.
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.
Reply With Quote
  #10  
Old 10-16-2008, 09:30 PM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default

The App.Settings file that you recommended is quite impressive, when I think of the work I'd have to do to accomplish this with a ListView. I'll try to make it work. Thanks for the suggestion.
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.
Reply With Quote
  #11  
Old 10-17-2008, 02:46 PM
AtmaWeapon's Avatar
AtmaWeaponStoring external data for my program AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

Also keep in mind it's not that tough to roll your own version of what App.Settings does. I've attached a small example I wrote the other day (and forgot to post) that uses a text file with the format:
Code:
name=value
name=value
If you're particularly clever, you could use the strategy pattern to reduce the coupling between the settings class and the parsing logic (like MS should have done with the current framework). Then, you could change file formats on a whim with a minimum of effort. If you're interested, it would make a fun off-topic side modification. This would be quite useful for supporting multiple formats at the same time (for example, you could support INI files for legacy OR a newer text format for moving forwards.)
Attached Files
File Type: vb ApplicationSettings.vb (3.6 KB, 4 views)
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #12  
Old 11-06-2008, 07:57 AM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default Ordering of App.Settings

I note that I am allowed to choose to have the list sorted by name, or not sorted. Alpha by name doesn't really keep items logically together, not unless I mess with the names themselves quite a bit. And "not sorted" seems random; it does not preserve the entry order.

Is there an alternative? Is there a way to impose at least one level of hierarchy here, i.e., group similar items? I couldn't see any way on screen. Maybe you have to edit the xml file?
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.
Reply With Quote
  #13  
Old 11-06-2008, 08:41 AM
AtmaWeapon's Avatar
AtmaWeaponStoring external data for my program AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

There's not really any concept of grouping or organization in a settings file that I know of. If you want to add extra levels of hierarchy, your choices are to either use classes that have properties named after what you desire or to write your own settings parser.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #14  
Old 11-15-2008, 11:25 PM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default

I note that the user can make changes directly on the Property Grid, which is okay in many cases, but sometimes I'd like to react to the user clicking on a field on there and present a further input box or combo box or something. I can't seem to get the Property Grid to respond to any click events. What am I missing?

[EDIT, Sunday]

Maybe I have the wrong idea here. I'm looking to limit the user's choices beyond simply "integer." How does one implement minimum and maximum or discrete choices? By manipulating the Get and Set methods, I suppose?
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.

Last edited by ElderKnight; 11-16-2008 at 11:49 AM.
Reply With Quote
  #15  
Old 11-17-2008, 10:08 AM
AtmaWeapon's Avatar
AtmaWeaponStoring external data for my program AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

The answers to both of your questions are related.

Generally, the property grid presents a combobox when the type of the property is an enumerated type, but it can be useful in cases where there are a few valid values and you don't want to use enumerations.

To make a property that isn't an enumerated type present a combobox, you have to create a TypeConverter-derived class and assign your custom type converter to the class with TypeConverterAttribute. To make the type converter display a combobox, you have to override GetStandardValuesSupported to return true, and possibly GetStandardValuesExclusive. Then, you must override GetStandardValues to return a string array that represents all of the allowed values. Finally, you need to override ConvertFrom, ConvertTo, and probably CanConvertFrom and CanConvertTo to handle the plumbing of converting from the standard value string to the actual value.

If you want to display a UI with a few controls on it, you need a type editor. This is a little more straightforward and documented fairly well. Then, you use EditorAttribute to associate the type editor with the property.

To implement range restrictions on a property, all you can do is do range checking in your property setters and throw exceptions when the value is not valid. In WPF, the dependency property system can use coercion to make this friendlier but somewhat less intuitive.

I had a nice example 90% done, but Visual Studio ate my project and punished me for failing to save it. Here's a thread where I've already done this for a TypeConverter; that particular example was using what I consider to be a fairly bad practice (storing values that design-time needs remotely) but I think if you delete lines 88-96 you can be rid of that mess.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #16  
Old 11-17-2008, 11:52 AM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default

I've been studying examples, and it does appear that all this is do-able, and can be nicely organized. I'll look at your example, and I think I'll get it. Thanks.
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.
Reply With Quote
  #17  
Old 11-17-2008, 06:56 PM
Gruff's Avatar
GruffStoring external data for my program Gruff is offline
Bald Mountain Survivor

Retired Moderator
* Expert *
 
Join Date: Aug 2003
Location: Oregon, USA - deceased
Posts: 6,440
Default

Interesting. I did not even know the propertygrid control existed.
__________________
Burn the land and boil the sea
You can't take the sky from me


~T
Reply With Quote
  #18  
Old 11-17-2008, 10:32 PM
ElderKnightStoring external data for my program ElderKnight is offline
Senior Contributor

Forum Leader
 
Join Date: Oct 2003
Location: Central Florida
Posts: 1,275
Default

Just one more question (until the next one) -- are you limited to one (1) My.Settings file per application, or could you somehow use this technique to let the user maintain several additional external data files?
__________________
-- D.J.

I do not endorse any items advertised within this frame, and regret that the viewer is subjected to such.
Reply With Quote
  #19  
Old 11-18-2008, 08:46 AM
AtmaWeapon's Avatar
AtmaWeaponStoring external data for my program AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

If you want the "automagic" support, I think you are limited to a single file. I admit I haven't put a lot of study to the subject though.

If you write a custom settings framework of course it can support any number of files you want.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #20  
Old 11-25-2008, 09:54 AM
whaaat whaaat is offline
Freshman
 
Join Date: Feb 2008
Posts: 48
Default

Question about using My.Settings.....

What if you have an array of 10 values assigned to MyArray(9) say Int16. How can I use My.Settings to save and retrieve these values?
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Storing external data for my program
Storing external data for my program
Storing external data for my program Storing external data for my program
Storing external data for my program
Storing external data for my program
Storing external data for my program Storing external data for my program Storing external data for my program Storing external data for my program Storing external data for my program Storing external data for my program Storing external data for my program
Storing external data for my program
Storing external data for my program
 
Storing external data for my program
Storing external data for my program
 
-->