What is the best way to bind WPF properties to ApplicationSettings in C#? Is there an automatic way like in a Windows Forms Application? Similar to this question, how (and is it possible to) do you do the same thing in WPF?
问题:
回答1:
You can directly bind to the static object created by Visual Studio.
In your windows declaration add:
xmlns:p="clr-namespace:UserSettings.Properties"
where UserSettings
is the application namespace.
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 example when you close your application:
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
Properties.Settings.Default.Save();
base.OnClosing(e);
}
回答2:
In case you are a VB.Net developer attempting this, the answer is a smidge different.
xmlns:p="clr-namespace:ThisApplication"
Notice the .Properties isn't there.
In your binding it's MySettings.Default, instead of Settings.Default - since the app.config stores it differently.
<TextBlock Height={Binding Source={x:Static p:MySettings.Default}, Path=Height, ...
After a bit of pulling out my hair, I discovered this. Hope it helps
回答3:
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} ... />
回答4:
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.
回答5:
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.
回答6:
I like to do it through the ViewModel and just do the binding as normal in the XAML
public Boolean Value
{
get
{
return Settings.Default.Value;
}
set
{
Settings.Default.SomeValue= value;
Settings.Default.Save();
Notify("SomeValue");
}
}
回答7:
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!