views:

1214

answers:

7

hi there,

we're currently planning a larger WPF LoB application and i wonder what others think being the best practice for storing lots of UI settings e.g.

  • Expander States
  • Menu orders
  • Sizing Properties
  • etc...

i don't like the idea of having dozens of stored values using the delivered SettingsProvider (i.e. App.config file) although it can be used to store it in an embedded database using a custom SettingsProvider. being able to use some kind of databinding is also a concern. Has anyone had the same problems?

What did you do to store lots of ui user settings?

+1  A: 

Seems to be losing popularity for some reason; but the registry has always been an appropriate place for these kinds of settings.

DancesWithBamboo
The registry is absolutely not the right place anymore. Registries get corrupted, inappropriate use can lead to security issues, and potentially violate LUA/UAC principles. http://secureapps.blogspot.com/2006/10/windows-registry-application-security.html
John Rudy
Well, the UI settings are hardly security relevant, are they?
Treb
They're easily corruptible and prone to errors. I would rather have them easily accessible by common users.
thismat
Never mind security relevant, registry writing often creates LUA/UAC issues, the registry gets corrupted easily, etc. Microsoft themselves recommend against it these days, and in favor of IsolatedStorage or Environment.SpecialFolder.ApplicationData for these reasons.
John Rudy
+9  A: 

We store the preferences file here:

Environment.SpecialFolder.ApplicationData

Store it as xml "preferences" file so it's not so hard to get to and change if it ever gets corrupted.

So far this has worked much better than the registry for us, it's cleaner and easier to blow out if anything gets corrupted or needs to be reset.

thismat
+2  A: 

We store all in the Isolation Storage (we are running with ClickOnce). We have some object that we serialize (XmlSerializer).

Daok
+1  A: 

We use a custom SettingsProvider to store the config information in a table in the app's database. This is a good solution if you're already using a database.

Stu Mackellar
+1  A: 

In the Programming WPF by Chris Sells & Ian Griffiths it says

The preferred setting mechanism for WPF application is the one provided by .NET and VS: the ApplicationSettingBase class from the System.Configuration namespace with the built-in designer.

aogan
Unfortunately the settings designer (in vs2008) materialises any settings you set in the designer as DefaultSettingValueAttribute entries in the settings.Designer.vb. There seems to be no way to turn this off. If you edit the config file by hand, then the next time you edit in the settings designer it will resync.This is so bad. It could result in an application being deployed with hardcoded defaults (which are somewhat hidden), that will take action if app.config settings are missing. http://tinyurl.com/3xyzz66
Topdown
+6  A: 

The quicker way to store UI settings is using the Properties.Settings.Default system. What can be nice with it is to use WPF binding to the value. Example here. Settins are automatically updated and loaded.

<Window ...
    xmlns:p="clr-namespace:UserSettings.Properties"
    Height="{Binding Source={x:Static p:Settings.Default}, Path=Height, Mode=TwoWay}" 
    Width="{Binding Source={x:Static p:Settings.Default}, Path=Width, Mode=TwoWay}" 
    Left="{Binding Source={x:Static p:Settings.Default}, Path=Left, Mode=TwoWay}" 
    Top="{Binding Source={x:Static p:Settings.Default}, Path=Top, Mode=TwoWay}">

...
protected override void OnClosing(System.ComponentModel.CancelEventArgs e) 
{ 
    Settings.Default.Save(); 
    base.OnClosing(e); 
}

The problem with that is that it quicky becomes a mess if your application is large.

Another solution (proposed by someone here) is to use the ApplicationData path to store your own preferences into XML. There you can build your own setting class and use the XML serializer to persist it. This approach enables you to do migration from versions to versions. While being more powerful, this method requires a bit more code.

decasteljau
+2  A: 

Digging into aogan's answer and combining it with decasteljau's answer and the blog post he referenced, here is an example that fills in some gaps that weren't clear to me.

The xaml file:

<Window ...
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:p="clr-namespace:MyApp"
    Height="{Binding Source={x:Static p:MyAppSettings.Default}, Path=MainWndHeight, Mode=TwoWay}"
    Width="{Binding Source={x:Static p:MyAppSettings.Default}, Path=MainWndWidth, Mode=TwoWay}"
    Left="{Binding Source={x:Static p:MyAppSettings.Default}, Path=MainWndLeft, Mode=TwoWay}"
    Top="{Binding Source={x:Static p:MyAppSettings.Default}, Path=MainWndTop, Mode=TwoWay}"
    ...

And the source file:

namespace MyApp
{
    class MainWindow ....
    {
        ...

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            MyAppSettings.Default.Save();
            base.OnClosing(e);
        }
    }

    public sealed class MyAppSettings : System.Configuration.ApplicationSettingsBase
    {
        private static MyAppSettings defaultInstance = ((MyAppSettings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new MyAppSettings())));
        public static MyAppSettings Default
        {
            get { return defaultInstance; }
        }

        [System.Configuration.UserScopedSettingAttribute()]
        [System.Configuration.DefaultSettingValueAttribute("540")]
        public int MainWndHeight
        {
            get { return (int)this["MainWndHeight"]; }
            set { this["MainWndHeight"] = value; }
        }

        [System.Configuration.UserScopedSettingAttribute()]
        [System.Configuration.DefaultSettingValueAttribute("790")]
        public int MainWndWidth
        {
            get { return (int)this["MainWndWidth"]; }
            set { this["MainWndWidth"] = value; }
        }

        [System.Configuration.UserScopedSettingAttribute()]
        [System.Configuration.DefaultSettingValueAttribute("300")]
        public int MainWndTop
        {
            get { return (int)this["MainWndTop"]; }
            set { this["MainWndTop"] = value; }
        }

        [System.Configuration.UserScopedSettingAttribute()]
        [System.Configuration.DefaultSettingValueAttribute("300")]
        public int MainWndLeft
        {
            get { return (int)this["MainWndLeft"]; }
            set { this["MainWndLeft"] = value; }
        }
    }
}
sean e