views:

4981

answers:

5

What is the best way to bind WPF properties to ApplicationSettings in C#? Is there an automatic way like in a Windows Forms Applicatoin? Similar to this question, how (and is it possible to) do you do the same thing in WPF?

+2  A: 

Kris, I'm not sure this is the best way to bind ApplicationSettings, but this is how I did it in Witty.

1) Create a dependency property for the setting that you want to bind in the window/page/usercontrol/container. This is case I have an user setting to play sounds.

    public bool PlaySounds
    {
        get { return (bool)GetValue(PlaySoundsProperty); }
        set { SetValue(PlaySoundsProperty, value); }
    }

    public static readonly DependencyProperty PlaySoundsProperty =
        DependencyProperty.Register("PlaySounds", typeof(bool), typeof(Options),
        new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnPlaySoundsChanged)));

    private static void OnPlaySoundsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        Properties.Settings.Default.PlaySounds = (bool)args.NewValue;
        Properties.Settings.Default.Save();
    }

2) In the constructor, initialize the property value to match the application settings

      PlaySounds = Properties.Settings.Default.PlaySounds;

3) Bind the property in XAML

      <CheckBox Content="Play Sounds on new Tweets" x:Name="PlaySoundsCheckBox" IsChecked="{Binding Path=PlaySounds, ElementName=Window, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

You can download the full Witty source to see it in action or browse just the code for options window.

Alan Le
the method by sasha (see other answer) is shorter
decasteljau
A: 

Also read this article on how it is done in BabySmash

You only need to back the Settings with DO (Like Alan's example) if you need the change notification! binding to the POCO Settings class will also work!

rudigrobler
+2  A: 

The easiest way would be to bind to an object that exposes your application settings as properties or to include that object as a StaticResource and bind to that.

Another direction you could take is creation your own Markup Extension so you can simply use PropertyName="{ApplicationSetting SomeSettingName}". To create a custom markup extension you need to inherit MarkupExtension and decorate the class with a MarkupExtensionReturnType attribute. John Bowen has a post on creating a custom MarkupExtension that might make the process a little clearer.

Richard Szalay
+13  A: 

You can directly bind to the static object created by VS.NET.

In your windows declaration add:

xmlns:p="clr-namespace:UserSettings.Properties"

Then you can add a binding to the correct setting:

<TextBlock Height={Binding Source={x:Static p:Settings.Default}, Path=Height, Mode=TwoWay} ... />

Now you can save the settings, per exemple when you close your application:

protected override void OnClosing(System.ComponentModel.CancelEventArgse)
{
    Settings.Default.Save();
    base.OnClosing(e); 
}
sacha
I was surprised that the `TwoWay` binding actually works in both ways. Nice. +1
Adam Badura
Note to searchers out there, *TwoWay* is REQUIRED or the settings won't be saved. Annoying to try and figure that one out.
Will
+1  A: 

I like the accepted answer, I ran into a special case though. I had my text box set as "read only" so that I can change the value of it only in the code. I couldn't understand why the value wasn't propagated back to the Settings although I had the Mode as "TwoWay".

Then, I found this: http://msdn.microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger.aspx

The default is Default, which returns the default UpdateSourceTrigger value of the target dependency property. However, the default value for most dependency properties is PropertyChanged, while the Text property has a default value of LostFocus.

Thus, if you have the text box with IsReadOnly="True" property, you have to add a UpdateSourceTrigger=PropertyChanged value to the Binding statement:

<TextBox Text={Binding Source={x:Static p:Settings.Default}, Path=myTextSetting, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged} ... />
Remus
best practice is to do it this way, imho.
Will