The situation
I have made an abstract Page for my UWP app: TestPage. This page contains some abstract items, in this simplified case just a string.
MVCE can be found here
C# code:
public abstract partial class TestPage : Page
{
public abstract string AbstractName { get; }
public TestPage()
{
InitializeComponent();
}
}
XAML:
<Page
x:Class="UWP_Test.TestPage"
...
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource TitleTextBlockStyle}"
Text="{x:Bind AbstractName}"/>
</Grid>
</Page>
I then have made two derived pages, or rather classes:
public sealed class TestPage1 : TestPage
{
public override string AbstractName => "TestPage1";
}
public sealed class TestPage2 : TestPage
{
public override string AbstractName => "TestPage2";
}
The problem
If I now try to navigate a Frame to either TestPage1 or TestPage2, this will work in a DEBUG build, but fail in a RELEASE build (System.AccessViolationException: 'Attempted to read or write protected memory.').
This is regardless of whether optimize code or .net native toolchain are enabled or disabled.
For my actual UWP app I would like to be able to use aforementioned principle to quickly make very similar pages that differ in a few aspects such as ItemTemplates, Viewmodels, etc.
I'd appreciate any leads that could either make this work in a release build or how to solve this (without creating a separate XAML file for each derived page, I already use this somewhere else and that is working in release).
Apparently, the way I want it to work does not seem to supported in a Release build, seemingly due to the way the .xaml and .cs files are compiled for a Release or Debug build.
For now I'm going to use multiple .xaml files, but I will keep trying to find a way to make this work and prevent a lot of exactly the same .xaml code (after all using multiple copies of the same code is asking for problems somewhere down the line).
I will update this answer accordingly when I do find an answer. (Thanks to Hamed and Mikah for the help so far)
Related
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.
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.
I believe the project metadata itself is somehow broken. I can make new pages, and new user controls. I can add them in XAML, as shown below (most of the generated code left out for brevity). This compiles:
<Page
x:Class="MyApp.Pages.MyPage"
…
xmlns:myControls="using:MyApp.Models">
<Grid>
<myControls:MyControl Name="MyControlName"></myControls:MyControl>
</Grid>
</Page>
And on the backend:
public sealed partial class MyPage : Page
{
public MyPage()
{
this.InitializeComponent();
}
}
And then the UserControl:
<UserControl
x:Class="MyApp.Models.MyControl"
…>
<Grid>
</Grid>
</UserControl>
And on the backend for that:
public sealed partial class MyControl : UserControl
{
public MyControl()
{
this.InitializeComponent();
}
}
As soon as I try and add a reference to that user control in the C# file of the page such as:
public sealed partial class MyPage : Page
{
public MyPage()
{
this.InitializeComponent();
this.MyControlName.Width = 10; // This line breaks it.
}
}
I get a compiler error, stating that " 'MyPage' does not contain a definition for 'MyControlName' and no extension method..."
This is true for any arbitrarily named user control I make, in any arbitrary location within the project, and any arbitrarily named page I make, likewise in any arbitrary location in the project. The project itself seems to no longer have the ability to enable a page's CS file to "see" a user control placed on a page. Other non-user controls (such as a TextBox) still work fine, however.
I know the references are all correct, because the project compiles and runs when that one line is removed from the C# file. The XAML side alone compiles. Also, note that this error persists regardless of what property or method of the control I am accessing, or even when I am setting the control to a new value (like this.MyControlName = new MyControl();). The page simply cannot find that definition for the control of that name in the C# file, even though the XAML-side can find that control's definition. The control's UI even displays properly on the page in design view.
If I try to work around the issue, such as explicitly declaring MyControl MyControlName { get; set; } on the MyPage.cs file, it builds and runs (even though it shouldn't, because that is a duplicate declaration of that name for a property on the MyPage class). Trying to interact with the UI elsewhere in the app, however, results in errors being throw along the lines of:
"this.<Project>k__BackingField was null"
My research has suggested this is an error normally associated with serialization. I am not ever explicitly using serialization. I imagine that serialization is used in the process of generating the xxx.g.i.cs files from the XAML, so perhaps it is an error in the project relating to how it governs generating those files?
The actual project is version-controlled using Visual Studio Team Services (VSTS). Rolling back to a changeset prior to this issue occurring (a changeset that compiled and ran fine) does not solve the problem.
I have gone so far as to use Visual Studio on a different PC, mapping the project (which has never been on that PC before), and getting a previous version prior to the issues. The problem still persists.
It seems as if the project itself and/or its metadata or generated files may have somehow been damaged, deleted, or corrupted. Somehow, this damage seems to extend back now to changesets in VSTS that were checked in and completely functional prior to this issue occurring.
The only last thing to note, is that my PC did crash (as in needing hard reset) while I had the project open in Visual Studio, and some of the files in the project (.cs and .xaml) were open at the time. I could see how this might corrupt files, but I do not see how this seems to have retroactively damaged the fully functional changesets prior to the crash.
This project consists of several months of development, and an extensive history on VSTS. It is completely unusable (since the core functionalities of the app all rely on user controls). The only solution I can think of is to create another project in the solution, and copy and paste the code from the files into new files in that project. I would still like, however, to fix the existing project if possible, so that the hundreds of previous changesets are usable still. Any ideas on how to fix this (or even where to begin looking for an issue) would be greatly appreciated!
I have a small window that I am trying to load when my application starts. Here is the (loose) XAML:
<ctrl:MainWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:Controls;assembly=Controls">
<Grid>
<ctrl:ConnectionStatusIndicator/>
<TextBlock Grid.Row="2" Text="{Resx ResxName=MyApp.MainDialog, Key=MyLabel}"/>
</Grid>
</ctrl:MainWindow>
Notice the custom control called ConnectionStatusIndicator. The code for it is:
using System.Windows;
using System.Windows.Controls;
namespace Controls
{
public class ConnectionStatusIndicator : Control
{
public ConnectionStatusIndicator()
{
}
static ConnectionStatusIndicator()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ConnectionStatusIndicator),
new FrameworkPropertyMetadata(typeof(ConnectionStatusIndicator)));
IsConnectedProperty = DependencyProperty.Register("IsConnected", typeof(bool), typeof(ConnectionStatusIndicator), new FrameworkPropertyMetadata(false));
}
public bool IsConnected
{
set { SetValue(IsConnectedProperty, value); }
get { return (bool)GetValue(IsConnectedProperty); }
}
private static DependencyProperty IsConnectedProperty;
}
}
Now, here is where it gets weird (to me, at least). With the XAML as it appears above, my application will build and run just fine. However, if I remove the following line:
<ctrl:ConnectionStatusIndicator/>
or event move it one line down, I get the following error:
Additional information: 'Cannot create unknown type
'{http://schemas.microsoft.com/winfx/2006/xaml/presentation}Resx'.'
Line number '13' and line position '33'.
What is really strange to me is that, if I replace ConnectionStatusIndicator with another custom control from the same assembly, I get the error. The other custom control is very similar, but has a few more properties.
Can anyone explain what is going on here?
The Resx markup extension belongs to the Infralution.Localization.Wpf namespace but also does something a bit hackish and attempts to register itself to the http://schemas.microsoft.com/winfx/2006/xaml/presentation xml namespace to allow developers to use it as {Resx ...} instead of having to declare the namespace in XAML and use the extension with a prefix {resxNs:Resx ...}.
I believe that if you clean up your solution and possible delete your *.sou file the project will build as expected, but a sure way to solve this will be to add an xmlns declaration for Infralution.Localization.Wpf and use the extension with the xmlns prefix:
<ctrl:MainWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:Controls;assembly=Controls"
xmlns:loc="clr-namespace:Infralution.Localization.Wpf;assembly=Infralution.Localization.Wpf">
<Grid>
<ctrl:ConnectionStatusIndicator/>
<TextBlock Grid.Row="2" Text="{loc:Resx ResxName=MyApp.MainDialog, Key=MyLabel}"/>
</Grid>
</ctrl:MainWindow>
Also, for anyone interested, the "hack" is in these lines in the localization library:
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "Infralution.Localization.Wpf")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2007/xaml/presentation", "Infralution.Localization.Wpf")]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2008/xaml/presentation", "Infralution.Localization.Wpf")]
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.