Winforms - Dynamic Load / Save Settings - c#

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).

Related

Sitecore - Programatically modify the source field of a template

Currently, all the templates that we have created have source fields whose path is a string.
e.g. :
"sitecore/content/Test"
Now if I want to move the Test folder to
sitecore/content/Shared/Tags/Test
the links are broken.
If i manually change this to use the GUID (Using the build option), I get :
datasource={62CF8494-B148-4B2E-9D36-52EC4CD75E13}&database=master
If i now move the test folder around, my links remain as is.
I wanted to write a routine that runs through the tree and updates all the source fields for my templates (in a particular folder only), to contain the GUID and db name.
Is this possible?
I tried doing this in the Process method of a class that inherits from PublishItemProcessor and added the appropriate entry in the web.config. This method is called, but the Source property of the field is read only and cannpt be modified.
Any ideas?
Thanks in advance.
The best/most efficient option here would be to use Sitecore Powershell Extensions to modify the items.
This is a good reference point: https://sitecorepowershell.gitbooks.io/sitecore-powershell-extensions/content/working-with-items.html
You could also do this in code.
You need to write a routine (code or SPE) that starts with the /sitecore/templates/user defined or whatever your root folder is.
Recurse thru the tree and get all items that have the template: Template Field. Then you can check value of the the Source field. If it is the one you want to change, update the value and save the item.
Remember to publish the templates tree after updating all the values.

How do you write out a blank version of your config when a program is first run? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I've been making a command line tool in c# and we've ended up using a config for some parameters that will only really need setting once. Rather than provide a UI for these I was told to just set up a blank config and if the values weren't set provide a message to say where the config was and to go set them.
This turned out to be remarkably difficult!
The things I needed to be able to do were as follows:
get the path to the config
save a blank config with stubs for the relevant properties
The tool was being released using CC.net and an msi created using wix. Unfortunately this was relevant!
Get the path to the config
This bit turned out to be very easy:
you just use something like this:
public string FileLocation
{
get { return Configuration.FilePath; }
}
private static Configuration Configuration
{
get { return OpenConfig(ConfigurationUserLevel.PerUserRoamingAndLocal); }
}
private static Configuration OpenConfig(ConfigurationUserLevel userLevel)
{
return ConfigurationManager.OpenExeConfiguration(userLevel);
}
There are two other values for the enum passed in there: None seems to point to where the app.config would be and PerUserRoaming always seems to point to somewhere that doesnt exist. I couldnt find out any more details about when this may be appropriate to use but in my case it appears not to be.
As just touched on above one of the confusing things about this call is that it will return the path of the file should one be saved/exist. This means that often this file wont exist! The unclear relationship between the ConfigurationManager and Settings (the autogenerated class derived from ApplicationSettingsBase) is what caused me a lot of pain!
save a blank config
A few stumbling blocks were as follows:
if you add a settings.Settings class this will also add an app.config. Unless you ship this with your installed program then you will see different behaviour between the installed version of the program and the dev version - one will create settings files using values from the app.config and the other wont. The simplest solution for me was to delete the app.config altogether.
I was trying to use the save method on Configuration which lets you specify that you save all properties (regardless of value being default) and lets you specify to save even if the configuration has not been modified. However calling this method with both flags set wont do anything - it appears that the settings you create in the designer in some way arent real until they get set - Configuration and ConfigurationManager are the older way of doing things and while ApplicationSettingsBase probably uses one or both of them they dont integrate nicely.
To make it more confusing, if you query the settings then they will have values (for strings they will have ""). However if you save the settings then these settings aren't saved to the location specified in the file! In fact no file will be created at all! Although if you have an app.config a file will be created if you use the force save method above as the defaults are specified in the app.config!
The solution appears to be to check for the default value in each of the properties and then set the default value. This looks like it should be a no-op but the getter doesnt follow the logic of 'if I dont have a setting I'll create it when queried' instead it just pretends one exists with the default value. Setting any value seems to actually create the setting.
var somethingUnSet = _settings.Something == "";
if (somethingUnset)
_settings.Something = "";
if(somethingUnset|| somethingElseUnset)
{
_settings.Save();
ExitWithError("config needs setting up at " + _settings.FileLocation);
return;
}
Finally this gave me the desired result - a file gets saved in the location specified by config manager with the empty properties that need filling in. Think a UI would have been quicker!!!
I was using a wrapped Settings object to facilitate changing values in tests without having to deal with a singleton. This also has the nice side effect that you can tack on extra code (like the file location) and not have to worry about the code gen overwriting stuff when you add more settings.
Just set all the Items in the .config File to nothing by first start like:
ConfigurationManager.appSettings["item1"] = "";
and check for the Value.
But why didn´t you just check if the parameters is set and if not Throw an error, i think you not need to clear a config file to check if its first start

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;

Sharepoint 2010 - SPPersistedObject.Update() doesn't update properties across different applications without iisreset

Working with Sharepoint 2010, I have a class that inherits SPPersistedObject with various settings:
[Serializable] class Settings : SPPersistedObject
{
[Persisted] private string setting1; // getters and setters etc. exist for each field
...
}
These settings (properties) are supposed to be globally accessible from the application code. Every time the value of one or more of them changes, Update() method is called so that other parts of the code (i.e. other aspx pages) may read the correct, up-to-date value.
This works fine as long as I'm only accessing properties within the same application that updated them, e.g.: http://abc:5100/.../test.aspx updates Settings.Setting1, calls Update(); and other :5100 pages will now see the new value in their code.
However - and this is my problem - when I read Settings.Setting1 property from, say, http://abc:26233 /.../temp.aspx, the old value (pre-Update) is retrieved instead of the new one. This leads me to believe that the property is read from some kind of in-memory copy instead of from the updated store. The new value is retrieved only if I manually use 'iisreset /restart' beforehand, but that is not desirable.
I would greatly appreciate it if someone has any idea on how to update/read the properties so that the change is reflected across the entire farm, i.e. the value is read from a common permanent store.
Solution found by w128:
The solution is to use the SPPersistedObject.Clone() method on your class, e.g. (not the actual code, but illustrates the point):
Settings s = (Settings)SettingsObj.Clone();
return s.Setting1; // returns updated value

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.

Categories

Resources