User Control throws "given key was not present in the dictionary" [duplicate] - c#

Does anyone know of some global state variable that is available so that I can check if the code is currently executing in design mode (e.g. in Blend or Visual Studio) or not?
It would look something like this:
//pseudo code:
if (Application.Current.ExecutingStatus == ExecutingStatus.DesignMode)
{
...
}
The reason I need this is: when my application is being shown in design mode in Expression Blend, I want the ViewModel to instead use a "Design Customer class" which has mock data in it that the designer can view in design mode.
However, when the application is actually executing, I of course want the ViewModel to use the real Customer class which returns real data.
Currently I solve this by having the designer, before he works on it, go into the ViewModel and change "ApplicationDevelopmentMode.Executing" to "ApplicationDevelopmentMode.Designing":
public CustomersViewModel()
{
_currentApplicationDevelopmentMode = ApplicationDevelopmentMode.Designing;
}
public ObservableCollection<Customer> GetAll
{
get
{
try
{
if (_currentApplicationDevelopmentMode == ApplicationDevelopmentMode.Developing)
{
return Customer.GetAll;
}
else
{
return CustomerDesign.GetAll;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}

I believe you are looking for GetIsInDesignMode, which takes a DependencyObject.
Ie.
// 'this' is your UI element
DesignerProperties.GetIsInDesignMode(this);
Edit: When using Silverlight / WP7, you should use IsInDesignTool since GetIsInDesignMode can sometimes return false while in Visual Studio:
DesignerProperties.IsInDesignTool
Edit: And finally, in the interest of completeness, the equivalent in WinRT / Metro / Windows Store applications is DesignModeEnabled:
Windows.ApplicationModel.DesignMode.DesignModeEnabled

You can do something like this:
DesignerProperties.GetIsInDesignMode(new DependencyObject());

public static bool InDesignMode()
{
return !(Application.Current is App);
}
Works from anywhere. I use it to stop databound videos from playing in the designer.

There are other (maybe newer) ways of specifying design-time data in WPF, as mentioned in this related answer.
Essentially, you can specify design-time data using a design-time instance of your ViewModel:
d:DataContext="{d:DesignInstance Type=v:MySampleData, IsDesignTimeCreatable=True}"
or by specifying sample data in a XAML file:
d:DataContext="{d:DesignData Source=../DesignData/SamplePage.xaml}">
You have to set the SamplePage.xaml file properties to:
BuildAction: DesignData
Copy to Output Directory: Do not copy
Custom Tool: [DELETE ANYTHING HERE SO THE FIELD IS EMPTY]
I place these in my UserControl tag, like this:
<UserControl
...
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
...
d:DesignWidth="640" d:DesignHeight="480"
d:DataContext="...">
At run-time, all of the "d:" design-time tags disappear, so you'll only get your run-time data context, however you choose to set it.
Edit
You may also need these lines (I'm not certain, but they seem relevant):
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"

When Visual Studio auto generated some code for me it used
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
...
}

And if you extensively use Caliburn.Micro for your large WPF / Silverlight / WP8 / WinRT application you could use handy and universal caliburn's Execute.InDesignMode static property in your view-models as well (and it works in Blend as good as in Visual Studio):
using Caliburn.Micro;
// ...
/// <summary>
/// Default view-model's ctor without parameters.
/// </summary>
public SomeViewModel()
{
if(Execute.InDesignMode)
{
//Add fake data for design-time only here:
//SomeStringItems = new List<string>
//{
// "Item 1",
// "Item 2",
// "Item 3"
//};
}
}

Accepted answer didn't work for me (VS2019).
After inspecting what was going on, I came up with this:
public static bool IsRunningInVisualStudioDesigner
{
get
{
// Are we looking at this dialog in the Visual Studio Designer or Blend?
string appname = System.Reflection.Assembly.GetEntryAssembly().FullName;
return appname.Contains("XDesProc");
}
}

I've only tested this with Visual Studio 2013 and .NET 4.5 but it does the trick.
public static bool IsDesignerContext()
{
var maybeExpressionUseLayoutRounding =
Application.Current.Resources["ExpressionUseLayoutRounding"] as bool?;
return maybeExpressionUseLayoutRounding ?? false;
}
It's possible though that some setting in Visual Studio will change this value to false, if that ever happens we can result to just checking whether this resource name exist. It was null when I ran my code outside the designer.
The upside of this approach is that it does not require explicit knowledge of the specific App class and that it can be used globally throughout your code. Specifically to populate view models with dummy data.

I have an idea for you if your class doesn't need an empty constructor.
The idea is to create an empty constructor, then mark it with ObsoleteAttribute. The designer ignores the obsolete attribute, but the compiler will raise an error if you try to use it, so there's no risk of accidentaly using it yourself.
(pardon my visual basic)
Public Class SomeClass
<Obsolete("Constructor intended for design mode only", True)>
Public Sub New()
DesignMode = True
If DesignMode Then
Name = "Paula is Brillant"
End If
End Sub
Public Property DesignMode As Boolean
Public Property Name As String = "FileNotFound"
End Class
And the xaml:
<UserControl x:Class="TestDesignMode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:AssemblyWithViewModels;assembly=AssemblyWithViewModels"
mc:Ignorable="d"
>
<UserControl.Resources>
<vm:SomeClass x:Key="myDataContext" />
</UserControl.Resources>
<StackPanel>
<TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding DesignMode}" Margin="20"/>
<TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding Name}" Margin="20"/>
</StackPanel>
</UserControl>
This won't work if you really need the empty constructor for something else.

Related

Prevent WPF User control to be rendered in Design mode [duplicate]

Does anyone know of some global state variable that is available so that I can check if the code is currently executing in design mode (e.g. in Blend or Visual Studio) or not?
It would look something like this:
//pseudo code:
if (Application.Current.ExecutingStatus == ExecutingStatus.DesignMode)
{
...
}
The reason I need this is: when my application is being shown in design mode in Expression Blend, I want the ViewModel to instead use a "Design Customer class" which has mock data in it that the designer can view in design mode.
However, when the application is actually executing, I of course want the ViewModel to use the real Customer class which returns real data.
Currently I solve this by having the designer, before he works on it, go into the ViewModel and change "ApplicationDevelopmentMode.Executing" to "ApplicationDevelopmentMode.Designing":
public CustomersViewModel()
{
_currentApplicationDevelopmentMode = ApplicationDevelopmentMode.Designing;
}
public ObservableCollection<Customer> GetAll
{
get
{
try
{
if (_currentApplicationDevelopmentMode == ApplicationDevelopmentMode.Developing)
{
return Customer.GetAll;
}
else
{
return CustomerDesign.GetAll;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
I believe you are looking for GetIsInDesignMode, which takes a DependencyObject.
Ie.
// 'this' is your UI element
DesignerProperties.GetIsInDesignMode(this);
Edit: When using Silverlight / WP7, you should use IsInDesignTool since GetIsInDesignMode can sometimes return false while in Visual Studio:
DesignerProperties.IsInDesignTool
Edit: And finally, in the interest of completeness, the equivalent in WinRT / Metro / Windows Store applications is DesignModeEnabled:
Windows.ApplicationModel.DesignMode.DesignModeEnabled
You can do something like this:
DesignerProperties.GetIsInDesignMode(new DependencyObject());
public static bool InDesignMode()
{
return !(Application.Current is App);
}
Works from anywhere. I use it to stop databound videos from playing in the designer.
There are other (maybe newer) ways of specifying design-time data in WPF, as mentioned in this related answer.
Essentially, you can specify design-time data using a design-time instance of your ViewModel:
d:DataContext="{d:DesignInstance Type=v:MySampleData, IsDesignTimeCreatable=True}"
or by specifying sample data in a XAML file:
d:DataContext="{d:DesignData Source=../DesignData/SamplePage.xaml}">
You have to set the SamplePage.xaml file properties to:
BuildAction: DesignData
Copy to Output Directory: Do not copy
Custom Tool: [DELETE ANYTHING HERE SO THE FIELD IS EMPTY]
I place these in my UserControl tag, like this:
<UserControl
...
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
...
d:DesignWidth="640" d:DesignHeight="480"
d:DataContext="...">
At run-time, all of the "d:" design-time tags disappear, so you'll only get your run-time data context, however you choose to set it.
Edit
You may also need these lines (I'm not certain, but they seem relevant):
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
When Visual Studio auto generated some code for me it used
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
...
}
And if you extensively use Caliburn.Micro for your large WPF / Silverlight / WP8 / WinRT application you could use handy and universal caliburn's Execute.InDesignMode static property in your view-models as well (and it works in Blend as good as in Visual Studio):
using Caliburn.Micro;
// ...
/// <summary>
/// Default view-model's ctor without parameters.
/// </summary>
public SomeViewModel()
{
if(Execute.InDesignMode)
{
//Add fake data for design-time only here:
//SomeStringItems = new List<string>
//{
// "Item 1",
// "Item 2",
// "Item 3"
//};
}
}
Accepted answer didn't work for me (VS2019).
After inspecting what was going on, I came up with this:
public static bool IsRunningInVisualStudioDesigner
{
get
{
// Are we looking at this dialog in the Visual Studio Designer or Blend?
string appname = System.Reflection.Assembly.GetEntryAssembly().FullName;
return appname.Contains("XDesProc");
}
}
I've only tested this with Visual Studio 2013 and .NET 4.5 but it does the trick.
public static bool IsDesignerContext()
{
var maybeExpressionUseLayoutRounding =
Application.Current.Resources["ExpressionUseLayoutRounding"] as bool?;
return maybeExpressionUseLayoutRounding ?? false;
}
It's possible though that some setting in Visual Studio will change this value to false, if that ever happens we can result to just checking whether this resource name exist. It was null when I ran my code outside the designer.
The upside of this approach is that it does not require explicit knowledge of the specific App class and that it can be used globally throughout your code. Specifically to populate view models with dummy data.
I have an idea for you if your class doesn't need an empty constructor.
The idea is to create an empty constructor, then mark it with ObsoleteAttribute. The designer ignores the obsolete attribute, but the compiler will raise an error if you try to use it, so there's no risk of accidentaly using it yourself.
(pardon my visual basic)
Public Class SomeClass
<Obsolete("Constructor intended for design mode only", True)>
Public Sub New()
DesignMode = True
If DesignMode Then
Name = "Paula is Brillant"
End If
End Sub
Public Property DesignMode As Boolean
Public Property Name As String = "FileNotFound"
End Class
And the xaml:
<UserControl x:Class="TestDesignMode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:AssemblyWithViewModels;assembly=AssemblyWithViewModels"
mc:Ignorable="d"
>
<UserControl.Resources>
<vm:SomeClass x:Key="myDataContext" />
</UserControl.Resources>
<StackPanel>
<TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding DesignMode}" Margin="20"/>
<TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding Name}" Margin="20"/>
</StackPanel>
</UserControl>
This won't work if you really need the empty constructor for something else.

Visual Studio runs WPF project in Designer [duplicate]

Does anyone know of some global state variable that is available so that I can check if the code is currently executing in design mode (e.g. in Blend or Visual Studio) or not?
It would look something like this:
//pseudo code:
if (Application.Current.ExecutingStatus == ExecutingStatus.DesignMode)
{
...
}
The reason I need this is: when my application is being shown in design mode in Expression Blend, I want the ViewModel to instead use a "Design Customer class" which has mock data in it that the designer can view in design mode.
However, when the application is actually executing, I of course want the ViewModel to use the real Customer class which returns real data.
Currently I solve this by having the designer, before he works on it, go into the ViewModel and change "ApplicationDevelopmentMode.Executing" to "ApplicationDevelopmentMode.Designing":
public CustomersViewModel()
{
_currentApplicationDevelopmentMode = ApplicationDevelopmentMode.Designing;
}
public ObservableCollection<Customer> GetAll
{
get
{
try
{
if (_currentApplicationDevelopmentMode == ApplicationDevelopmentMode.Developing)
{
return Customer.GetAll;
}
else
{
return CustomerDesign.GetAll;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
}
I believe you are looking for GetIsInDesignMode, which takes a DependencyObject.
Ie.
// 'this' is your UI element
DesignerProperties.GetIsInDesignMode(this);
Edit: When using Silverlight / WP7, you should use IsInDesignTool since GetIsInDesignMode can sometimes return false while in Visual Studio:
DesignerProperties.IsInDesignTool
Edit: And finally, in the interest of completeness, the equivalent in WinRT / Metro / Windows Store applications is DesignModeEnabled:
Windows.ApplicationModel.DesignMode.DesignModeEnabled
You can do something like this:
DesignerProperties.GetIsInDesignMode(new DependencyObject());
public static bool InDesignMode()
{
return !(Application.Current is App);
}
Works from anywhere. I use it to stop databound videos from playing in the designer.
There are other (maybe newer) ways of specifying design-time data in WPF, as mentioned in this related answer.
Essentially, you can specify design-time data using a design-time instance of your ViewModel:
d:DataContext="{d:DesignInstance Type=v:MySampleData, IsDesignTimeCreatable=True}"
or by specifying sample data in a XAML file:
d:DataContext="{d:DesignData Source=../DesignData/SamplePage.xaml}">
You have to set the SamplePage.xaml file properties to:
BuildAction: DesignData
Copy to Output Directory: Do not copy
Custom Tool: [DELETE ANYTHING HERE SO THE FIELD IS EMPTY]
I place these in my UserControl tag, like this:
<UserControl
...
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
...
d:DesignWidth="640" d:DesignHeight="480"
d:DataContext="...">
At run-time, all of the "d:" design-time tags disappear, so you'll only get your run-time data context, however you choose to set it.
Edit
You may also need these lines (I'm not certain, but they seem relevant):
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
When Visual Studio auto generated some code for me it used
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
...
}
And if you extensively use Caliburn.Micro for your large WPF / Silverlight / WP8 / WinRT application you could use handy and universal caliburn's Execute.InDesignMode static property in your view-models as well (and it works in Blend as good as in Visual Studio):
using Caliburn.Micro;
// ...
/// <summary>
/// Default view-model's ctor without parameters.
/// </summary>
public SomeViewModel()
{
if(Execute.InDesignMode)
{
//Add fake data for design-time only here:
//SomeStringItems = new List<string>
//{
// "Item 1",
// "Item 2",
// "Item 3"
//};
}
}
Accepted answer didn't work for me (VS2019).
After inspecting what was going on, I came up with this:
public static bool IsRunningInVisualStudioDesigner
{
get
{
// Are we looking at this dialog in the Visual Studio Designer or Blend?
string appname = System.Reflection.Assembly.GetEntryAssembly().FullName;
return appname.Contains("XDesProc");
}
}
I've only tested this with Visual Studio 2013 and .NET 4.5 but it does the trick.
public static bool IsDesignerContext()
{
var maybeExpressionUseLayoutRounding =
Application.Current.Resources["ExpressionUseLayoutRounding"] as bool?;
return maybeExpressionUseLayoutRounding ?? false;
}
It's possible though that some setting in Visual Studio will change this value to false, if that ever happens we can result to just checking whether this resource name exist. It was null when I ran my code outside the designer.
The upside of this approach is that it does not require explicit knowledge of the specific App class and that it can be used globally throughout your code. Specifically to populate view models with dummy data.
I have an idea for you if your class doesn't need an empty constructor.
The idea is to create an empty constructor, then mark it with ObsoleteAttribute. The designer ignores the obsolete attribute, but the compiler will raise an error if you try to use it, so there's no risk of accidentaly using it yourself.
(pardon my visual basic)
Public Class SomeClass
<Obsolete("Constructor intended for design mode only", True)>
Public Sub New()
DesignMode = True
If DesignMode Then
Name = "Paula is Brillant"
End If
End Sub
Public Property DesignMode As Boolean
Public Property Name As String = "FileNotFound"
End Class
And the xaml:
<UserControl x:Class="TestDesignMode"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vm="clr-namespace:AssemblyWithViewModels;assembly=AssemblyWithViewModels"
mc:Ignorable="d"
>
<UserControl.Resources>
<vm:SomeClass x:Key="myDataContext" />
</UserControl.Resources>
<StackPanel>
<TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding DesignMode}" Margin="20"/>
<TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding Name}" Margin="20"/>
</StackPanel>
</UserControl>
This won't work if you really need the empty constructor for something else.

XAML Designer Crashes with Self-Registering ViewModel

The XAML designer crashes visual studio 2010 if the view model that is set as the Data Context registers itself in a static class.
View
<Window x:Class="CTL.Editor.View.EditorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:editor="clr-namespace:CTL.Editor.ViewModel.Editor"
Height="300" Width="300">
<Window.DataContext>
<editor:EditorWindowViewModel />
</Window.DataContext>
<Grid>
</Grid>
</Window>
ViewModel:
public EditorWindowViewModel()
{
ApplicationViewModel.EditorWindows.Add(this);
}
~EditorWindowViewModel()
{
ApplicationViewModel.EditorWindows.Remove(this);
}
Is there any way around this? Maybe a # directive?
You can use the DesignerProperties.IsInDesignMode to supress execution while in design mode. Just wrap your code in an if statement: if(!DesignerProperties.IsInDesignTool)
However it is often a good idea to find the root cause of the problem by debugging the designer exception. Here is an good article that should get you started.
For those seeking a bit more detail than Postlagerkarte's answer:
A way to use IsInDesignMode that is MVVM-friendly is shown below.
if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
{
....
}
My issue was caused by the fact that ApplicationViewModel's constructor what loading a config file and apparently Visual Studio didn't like that, didn't find the file or didn't search for the file in the right place when it was running my code.
What I ended up doing was:
public static bool DesignMode
{
get { return DesignerProperties.GetIsInDesignMode(new DependencyObject()); }
}
static ApplicationViewModel()
{
if (!DesignMode)
{
Configuration = Configuration.LoadConfigurationDocument();
}
}
Note: There is a Configuration static member on ApplicationViewModel and a Configuration class which loads the config.

Data binding window title to application resource

Currently I'm doing it so:
public MainWindow()
{
InitializeComponent();
Title = Properties.Resources.WindowName;
}
How to do the same through the WPF binding?
EDIT: It still doesn't work in XAML.
Environment:VS2010, .NET 4.0, Windows 7.
Reproduction steps:
Create class library ClassLibrary1 with code:
namespace ClassLibrary1
{
static public class Class1
{
static public string Something
{
get { return "something"; }
}
}
}
Create WPF windows application in VS2010 .NET 4.0.
Edit main window's XAML:
<Window x:Class="ahtranslator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ClassLibrary1="clr-namespace:ClassLibrary1;assembly=ClassLibrary1"
Title="{Binding Source={x:Static ClassLibrary1:Class1}, Path=Something}"
Height="350" Width="525" Icon="/ahtranslator;component/Icon1.ico" WindowStyle="SingleBorderWindow" ShowInTaskbar="False" DataContext="{Binding}">
...
Compilation error message:
MainWindow.xaml(7,130): error MC3029: 'ClassLibrary1:Class1' member is not valid because it does not have a qualifying type name.
Also I found this topic My.Resources in WPF XAML?.
And it seems all should work but it doesn't.
Microsoft doesn't give description for this error message. Only another topic in help forum http://social.msdn.microsoft.com/Forums/en/wpf/thread/4fe7d58d-785f-434c-bef3-31bd9e400691, which doesn't help either.
In code it would look like this i think:
Binding titleBinding = new Binding("WindowName");
titleBinding.Source = Properties.Resources;
this.SetBinding(Window.Title, titleBinding);
This only makes sense if changes may occur to the title and the binding will be notified of those changes (WindowName has to either be a Dependency Property or Resources needs to implement INotifyPropertyChanged)
If Properties is a namespace (as would be the case with the default VS-generated properties) you need to declare it somewhere using xmlns & use x:Static:
<Window
...
xmlns:prop="clr-namespace:App.Properties"
Title="{Binding Source={x:Static prop:Resources.WindowName}}">
Another note: If you use the managed resources of Visual Studio you need to make sure that the access modifier of the properties is public, default is internal which will throw an exception since binding only works for public properties.
just remove this:
... ;assembly=ClassLibrary1"
I actually have the Title in a static resource defined at the top of the application and I bind the Title and anything else I want to it
<s:String x:Key="ApplicationName">My Application</s:String>
Have you tried to change the access modifier of the resource from internal to public?
I have just had some problem with that right now.
/// <summary>
/// Looks up a localized string similar to Has been impossible to load the configuration information.
/// </summary>
internal static string ERROR_NoConfigurationLoaded {
get {
return ResourceManager.GetString("ERROR_NoConfigurationLoaded", resourceCulture);
}
}
to
/// <summary>
/// Looks up a localized string similar to Has been impossible to load the configuration information.
/// </summary>
public static string ERROR_NoConfigurationLoaded {
get {
return ResourceManager.GetString("ERROR_NoConfigurationLoaded", resourceCulture);
}
}

Best practices for storing UI settings?

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?
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.
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. Settings 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 quickly 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.
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; }
}
}
}
We store all in the Isolation Storage (we are running with ClickOnce). We have some object that we serialize (XmlSerializer).
Seems to be losing popularity for some reason; but the registry has always been an appropriate place for these kinds of settings.
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.
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.

Categories

Resources