Visual Studio Settings.settings file - c#

Is there a way of creating a new setting in the Settings.settings file during run time?
For example, I want to write to the settings file from one class function, and read that value from a different class function. And no, I don't want to pass the values.
I know how to get values from the Settings.settings file
(value = Properties.Settings.Default.XXX)
I know how to update an existing value
(Properties.Settings.Default.XXX = newValue; Properties.Settings.Default.Save())
I want to know how I can add "Name", "Type", "Scope" and "Value" into the Settings.settings file during run time.
Any suggestions would be appreciated!
Thanks,
Ivar

The Issues
I believe Visual Studio generates code when you design the application settings and values, therefore at runtime this would not be easy and at worst impossible without a designer. However you can sometimes call upon design features at runtime.
You'll notice the code-behind has the properties in C# that you create in your designer. For example, I added a setting for:
Age [int] 30.
The code-behind has generated:
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("30")]
public int Age {
get {
return ((int)(this["Age"]));
}
set {
this["Age"] = value;
}
}
(The code generation is why you have strongly-typed settings)
I'm unsure if you could effect this same thing at runtime. You would have to generate code and feed it back to the JIT compiler dynamically or something like that. Or maybe there's another way I don't know about in my limited understanding of settings.
Suggestion/Workaround
I'd suggest figuring out an alternate/easier way instead of jumping through hoops. For example, make one setting a collection type that is serializable so it can store multiple values.
Then you can, for example, store multiple ages under just one setting:
Ages [System.Collections.ArrayList] {add multiple values programatically}
You might end up with C# code to manage it like:
System.Collections.ArrayList list = new System.Collections.ArrayList();
list.Add("1");
list.Add("30");
Properties.Settings.Default.Ages = list;
Properties.Settings.Default.Save();

Related

What is the difference between Settings.Default.[PropertyName] , Settings.Default.Properties and Settings.Default.PropertyValues?

I wanted to know the difference between these 3 Settings.Default.<PropertyName> , Settings.Default.Properties and Settings.Default.PropertyValues .
I have a wpf window that would dynamically generate controls based on these Settings and then one can update the Settings values
I first used Settings.Default.Properties Collection , but I believe it does not update the values in either config or the physical settings file in the user folder.
So I used reflection to update , But I still couldn't figure how to obtain
values by Reflection . (May still need to research on this)
Settings.Default.GetType().GetProperty(propertyName,
typeof(string)).SetValue(source, fileDialog.FileName, null);
Settings.Default.Save();
Settings.Default.Reload();
Then I saw Settings.Default.PropertyValues has the latest updated values and tested that in debug mode,
string properyValue =
Convert.ToString(Settings.Default.PropertyValues[propertyName].PropertyValue);
strangely they don't seem to be working when I created the installer and exe . Still to figure what exactly wrong.
Can someone point me out if I am complicating things and missing something?
Update 1
After nflash's comment , I checked when the file was created. The file was not created when the application starts for all 3 , I even called Settings.Default.Save right at the start but it doesn't create the file Settings.Default.<PropertyName> , Settings.Default.Properties are instantiated but Settings.Default.PropertyValues not.
Only once I make a change in the Settings and Save , the file is created.
Update2
Right now the solution that I came with is
source.GetType().GetProperty(setting.Name, typeof(string))
.SetValue(source, "NewValue", null);
As mentioned by nflash , it would be type safe (Although Reflection has it's demirits) . But the Settings.Default.<PropertyName> is synchronized and instantiated correctly hence.
Just want to add that you can only change settings with "User" scope. When you save the new value of the setting the value is not saved in the config in the application path but instead it is saved in the user.config inside the %localappdata% folder (%localappdata%\CompanyName\ApplicationName_someGUID\AppVersion)
Update:
About your last update, the user.config file is only created when you save a setting with a value different from the default value of the setting.
I'm not sure if you still have questions about this, so I'm trying to add more info:
Settings.Default.<PropertyName> as wonko79 pointed out is just a property accessor to the corresponding value. If you look at the code behind the settings (or just Go To Definition of the property) you will see something like this:
public string PropertyName {
get {
return ((string)(this["PropertyName"]));
}
set {
this["PropertyName"] = value;
}
}
The array operator is accessing the underlying structure that holds the values that in fact is the PropertyValues.
The difference between the Properties and PropertyValues is a little bit trickier. These are really two different structures (one is a SettingsPropertyCollection and the other is a SettingsPropertyValueCollection). The Properties property is defined in the ApplicationSettingsBase class and the PropertyValues is defined in the SettingsBase class.
The SettingsProperty class (elements of the SettingsPropertyCollection) contains information about the setting itself (metadata?) and its default value.
The SettingsPropertyValue class (elements of the SettingsPropertyValueCollection) contains the actual value of the setting and some additional control information, like if the value is dirty, if it is using default value, etc.
In the end of the day this is all how .NET internally manages the Settings and all that we need to know is how to get and set these settings.
I always like to work with the properties that the setting designer generates as it is strongly typed and already makes the cast to the corresponding type. Also using the Properties or PropertyValues requires a string as a parameter and in case of a typo I will only get an error in runtime as opposed to the compile error that I get if misspell the name of the property.
To save the settings after changing them you have to call
Settings.Default.Save();
Settings.Default.<PropertyName> is a property accessor to the corresponding settings value.
Settings.Default.Properties is a collection of all settings in your settings file.
Settings.Default.PropertyValues is a collection of all values of the settings in your settings file.
Maybe Using Settings in C# is a good starting point to read.
The article mentioned by user1064248 is good info, but does not address the PropertyValues issue. I cannot add anything to the good advice from Rameez and nflash except for this pragmatic advice: If you wish to force PropertyValues to populate, you need only to force a value to change. In my settings I have a DateTime property called "Timestamp" and if you put this in the form Load event, you will find that nn1 is zero, and nn2 contains the count all of the properties:
int nn1 = Properties.Settings.Default.PropertyValues.Count;
Properties.Settings.Default.Timestamp = DateTime.UtcNow; // Forces PropertyValues to load
int nn2 = Properties.Settings.Default.PropertyValues.Count;

How to specify order of debugger visualizers in Visual Studio

I've been working on a debugger visualizer for Visual Studio for some time and while the actual visualizer works fine. The problem is that it always places itself at the top of the visualizer list when examining a variable which really annoys some of the users who rather have Text as the top one (since the top one is also default when opening VS).
I can't find any support for this on DialogDebuggerVisualizer or DebuggerVisualizerAttribute which were my first thoughts so I've been scouring SO/MSDN/Google for information on how to affect the sort order of the visualizers (preferably to put mine last in the list) but to no avail.
Below is how I register my visualizer, it then just shows a form based on the value that is being visualized.
using Microsoft.VisualStudio.DebuggerVisualizers;
[assembly: System.Diagnostics.DebuggerVisualizer(
typeof(Shorthand.VSAddins.JsonVisualizer.JsonVisualizer),
typeof(VisualizerObjectSource),
Target = typeof(string),
Description = "Json Visualizer")]
namespace Shorthand.VSAddins.JsonVisualizer
{
public class JsonVisualizer : DialogDebuggerVisualizer
{
protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
{
var json = objectProvider.GetObject() as string;
var form = new VisualizerForm { Json = json };
windowService.ShowDialog(form);
}
}
}
Does anyone know if it is possible to affect the order of the visualizers or should I just let it be?
I don't think there is a solution. But there is a workaround:
Define your own Text Visualizer and put appropriate DebuggerVisualizer attribute before the attribute of your JsonVisualizer. The result will be that string will be readable by default and Json Visualizer can be chosen. A window with a multi-line textbox is not too much work.
It is probably not even necessary to write visualizer. It should be possible to use internal one but I don't know its name (Which class is used for "Text Visualizer"?).
It will always appear first, by design. The under the hood cast has found the best match for the variable it is reflecting on.
however, you could do either of two things. You could make the visualizer only appear when the sting contains ':'
Or you could use reflection to reorder the visualisers by adding them to the end of the collection in the order you want, then removing the originals from the collection.
For the latter you will most likely have to change the collection from readonly to writable. Via reflection.
There is no reliable source to draw on other than your will to succeed.
I guess that VS 'under the hood' can distinguish between type of string and type of xml quite easily, but Xml is just a string too, so a key question here would be, how does VS tell the difference between the two?
Could you dissect the VS XML visualizer to see how it works (even if you have to use reflector on the DLL to do it, you might get to see the method that works it out)

Save/Read object values using Properties.Settings

I want to save the state of my object when the software exit and restore it when the software loads. Im doing this (code below) now, but I think there must be another bether/smarter way to do that. :)
Ive read a little about Databing, but for this I would need to modify MyClass, deriving it from CollectionBase, etc.. Do you think it is a good ideia?
One more thing, is there a way to store a Point*F* (PointFFFF no Point) directly in Properties.Settings (I could not find it in browse)?
LoadConfig()
{
MyClass.ItemA = Properties.Settings.Default.ItemA;
}
SaveConfig()
{
Properties.Settings.Default.ItemA = MyClass.ItemA;
Settings.Default.Save();
}
I see nothing wrong with it. Yes, you could certainly use bindings also. You can create settings for other non-primitive types by going to type "Browse..." and then select the type you want to save. You would be able to browse for System.Drawing.Point and use that. It'll serialize the value in the app.config file.

config and settings component for C#

I'm starting to design a config and settings component for an application.
I need an easy way to read dictionary style settings and also a way to store simple arrays into a persistence level.
is there a commonly used component already available ? (something like log4net for logging)
what options should I look into ?
You don't really need to do that: .NET BCL already has everything you need.
Take a look at App.Config and the ConfigurationManager class.
If you expand the Properties folder in the SolutionExplorer you should find a Settings.Settings item. Double clicking on this will open the settings editor. This enables you to declare and provide initial values for settings that can either be scoped to the application or the current user. Since the values are persisted in Isolated storage you do not need to worry about what privileges the user is executing under.
For a wee example:
I created a new string setting with the name Drink and a TextBox named drinkTextBox. The code to assign the current value to the text box is:
drinkTextBox.Text = Properties.Settings.Default.Drink;
and to update the value persisted:
Properties.Settings.Default.Drink = drinkTextBox.Text;
Properties.Settings.Default.Save();
Depending on how flexible you want it to be, you can use the build in Settings designer (go to Project Properties > Settings) and you can add settings there.
These are strongly typed and accessible through code.
It has built in features like Save, Load and Reload
We'll often create a sealed class that has a number of properties that wrap calls to the the System.Configuration.ConfigurationManager class. This allows us to use the standard configuration managagement capabilities offered by the class and the app/web.config file but make the data very easy to access by other classes.
For example we might create a property to expose the connection string to a database as
public static string NorthwindConnectionString
{
get{return ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString
}
While it creates a wrapper around one line of code, which we usually try to avoid, it does make certain confiuration properties accessible via intellisense and provides some insullation around changes to the location of underlying configuration data. If we wanted to move the connection string to the registry, we could do so without major impact to the application.
We find this most helpful when we have larger teams or when we need to hand off code from one team to another. It keeps people from needing to remember what the various settings were named in the config files and even where configuration information is stored (config file, database, registry, ini file, etc.)
Building a dictionary in the standard settings
Using the standard Settings, it isn't possible to store dictionary style settings.
To emulate the System.Collections.Specialized.StringDictionary,
what I've done in the past is used two of the System.Collections.Specialized.StringCollection typed settings (this is one of your options for the setting type).
I created one called Keys, and another called values. In a class that needs these settings I've created a static constructor and looped through the two StringCollections and built the StringDictionary into a public static property. The dictionary is then available when needed.
public static StringDictionary NamedValues = new StringDictionary();
public static ClassName() // static construtor
{
StringCollection keys = Properties.Settings.Default.Keys;
StringCollection vals = Properties.Settings.Default.Values;
for(int i = 0; i < keys.Count(); i++)
{
NamedValues.Add(keys[i], vals[i]);
}
}
For noddy apps I use appSettings. For enterprise apps I usually create some custom config sections. CodeProject has some excellent articles on this.
For your scenario of key/value pairs I'd probably use something like this.

Winforms - Dynamic Load / Save Settings

I have a "settings file" in my Winforms application called Settings.settings with a partial class for custom methods, etc. Is there a way to load / save dynamic settings based on arbitrary keys?
For example, I have some ListViews in my application in which I want to save / load the column widths; Instead of creating a width setting for each column for each list view I would like a simple method to load / save the widths automatically.
Below is an example of the save method I have tried:
internal sealed partial class Settings
{
public void SetListViewColumnWidths(ListView listView)
{
String baseKey = listView.Name;
foreach (ColumnHeader h in listView.Columns)
{
String key = String.Format("{0}-{1}", baseKey, h.Index);
this[key] = h.Width;
}
}
}
When running that code I get the error "The settings property 'TestsListView-0' was not found." Is there something I am missing?
Store your column width settings in an Xml Serializable object. Ie, something that implements IXmlSerializable then create a single setting entry of that type in Settings.settings.
A good option would probably be an Xml Serializable Dictionary. A quick google search found quite a few different blog posts that describe how to implement that.
As mentioned in other answers you'll need to ensure that this object is a User setting. You may also need to initialize the setting instance. Ie, create a XmlSerializableDictionary() instance and assign it to the setting if the setting is null. The settings subsystem doesn't create default instances of complex setting objects.
Also, if you want these settings to persist between assembly versions (ie, be upgradable) you will need to upgrade the settings on application startup. This is described in detail on Miha Markič's blog and Raghavendra Prabhu's blog.
I think the error
The settings property
'key' was not found.
occurs because the 'key' value does not exist in your settings file (fairly self-explanatory).
As far as I am aware, you can't add settings values programmatically, you might need to investigate adding all of the settings you need to the file after all, although once they are there, I think you'll be able to use the sort of code you've given to save changes.
To Save changes, you'll need to make sure they are 'User' settings, not 'Application'.
The Settings file is quite simple XML, so you might be able to attack the problem by writing the XML directly to the file, but I've never done it, so can't be sure it would work, or necessarily recommend that approach.
http://msdn.microsoft.com/en-us/library/cftf714c.aspx is the MSDN link to start with.
You can do Settings.Save() or similar on user settings, but note that such settings would NOT get persisted to the xxx.exe.config file in your app directory as you'd expect. They actually go somewhere deep inside the user folder (search your drive for xxx.exe.config to find it). Next time that you manually change xxx.exe.config in your app directory, the change will mysteriously not apply (the system is still using the saved one from the user directory).

Categories

Resources