Click here to Skip to main content
15,879,535 members
Articles / Desktop Programming / WPF

WPF Dynamic Application Settings

Rate me:
Please Sign up or sign in to vote.
3.82/5 (11 votes)
5 Oct 2011CPOL4 min read 33.9K   494   24   2
WPF Dynamic Application Settings

Introduction

The Property Settings capability provided by Visual Studio is quite good for many applications, but is not able to support Application level changes where several applications use the same code base. This paper covers a way to provide each application with its own settings that can be easily maintained.

Background

We had several applications that could use the same Views but for slight differences. To accommodate the requirements for the different applications, we could have created new views, or add properties to the ViewModel, and use these properties in the Views. This added unnecessary complexity to the ViewModels, and also might require some way of customizing the ViewModel for each application when it would otherwise not be required. There are also a lot of other disadvantages to using Binding, including performance, and maintenance as images change in the Views.

Image 1

One of the thoughts was to use the existing Settings. This would have allowed all the paths for the icons to be specified in the Settings file, and the XAML in the view could directly access these settings. However, this did not work well on an application level. We could have created different settings files for each application, but then would have to include the right settings files in the build. The final solution was to use a static class with static properties, and then update those properties. This has a lot of the advantages of the Setting approach, and each application could easily customize the values in this static class.

Implementation

The Settings file has to be static so that it is possible to bind to it from XAML without it interfering with the current DataContext. Thus by warping the settings in static properties, the following XAML will work where the namespace for the settings class is WpfDynamicSettings, and the name of the class is ApplicationSettings:

XML
<Window x:Class="WpfDynamicSettings.TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	      xmlns:settings="clr-namespace:WpfDynamicSettings"
	      Title="TestWindow" Height="200" Width="300">
	<Window.Resources>
	  <settings:ApplicationSettings x:Key="Settings"/>
	</Window.Resources>
	<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBlock Text="{Binding String1, Source={StaticResource Settings}}"
		Width="200" Margin="10"/>
    <TextBlock Text="{Binding String2, Source={StaticResource Settings}}"
			Width="200" Margin="10"/>
	</StackPanel>
</Window>

NOTE: I like to put the “xmlns:settings” and the “settings:ApplicationSettings” in the App.xaml resource or a dictionary referred to by the App.xaml file so that these lines only have to be defined once in the application.

The ApplicationSettings file can be quite simple, but there has to be some way to update the values for the settings, and for this I use a method I named Update:

C#
public class ApplicationSettings
{
	  public static string String1 { get; protected set; }
	  public static string String2 { get; protected set; }

	  static ApplicationSettings()
	  {
	    String1 = String1 ?? "Default 1";
	    String2 = String2 ?? "Default 2";
	  }

	  //For using method initialization (vs. class method)
	  public static void Update (string string1 = null, string string2 = null)
	  {
	    String1 = string1 ?? String1;
	    String2 = string2 ?? String2;
	  }
}

The constructor is only required if there are to be default values (required for our use since it meant that the legacy applications did not have to be changed to support the updated Views).

The method “Update” is only needed for one of the ways of initializing the ApplicationSettings file to the values for the specific application. Note: I made all arguments optional, and then only updated corresponding properties if they were not null, not changing the current value. This supports named arguments, which I think is much clearer:

C#
ApplicationSettings.Update(
	string1: "Updated Application 1 String 1",
	string2: "Updated Application 1 String 2");

It also allows specifying only those settings that need to be changed, giving a tremendous flexibility. If this is the only way the user wants to update the ApplicationSettings, then all the properties can use a private set instead of a protected set. The protected set is for using a derived class to update the values:

C#
class Custom1ApplicationSettings : ApplicationSettings
{
  static Custom1ApplicationSettings()
  {
    // This does not work more than once
    String1 = "Custom 1 String 1";
    String2 = "Custom 1 String 2";
  }

  public static void Update()
  {
    String1 = "Custom 1 String 1";
    String2 = "Custom 1 String 2";
  }
}

The constructor is not required, and in fact should not be in the class since if the Update method is used, it is redundant. The interesting thing is that the constructor for the parent class only executes after the Update for the derived class has executed. This is the reason the “??” operator is used in setting all the default values for the constructor in the parent class. However, when the Update in the parent class is called, the constructor executes first. This is the reason that the “??” operator is used in the parent class’s Update method so the Update method does not overwrite the default values with null.

For my needs, I wanted the ApplicationSettings class to be initialized when the application started, so updated the App.xaml to handle the Startup event as follows:

XML
<Application x:Class="WpfDynamicSettings.App"
	   xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
	   xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
	   Startup="AppStartup"
	   StartupUri="MainWindow.xaml">
	<Application.Resources>
	</Application.Resources>
</Application>

Then I added an event handler in the App.xaml.cs file that would initialize the ApplicationSettings file either using the class method:

C#
public partial class App : Application
{
  private void AppStartup(object sender, StartupEventArgs e)
  {
    Custom1ApplicationSettings.Update();
  }
}

Or using the Update method on the base class as follows:

C#
public partial class App : Application
{
  private void AppStartup(object sender, StartupEventArgs e)
  {
    ApplicationSettings.Update(
      string1: "Initialized in App startup 1",
      string2: "Initialized in App startup 2");
  }
}

The example I created has a combo box which allows the user to select whether to open a new form either using the Update method with the settings specified in the arguments in the base class, or the Update method in a derived class with the settings specified in the derived class. There are two different settings for each implementation. Also the App.xaml has code to set the settings, and code for both is in the App.xaml.cs file. We can enable either method, or disable both to see the results. The form that is used to demonstrate the concept is below. Just select the option from the combo box and the second window will be displayed. Use the close button to return to the first form.

Image 2

Image 3

Summary

This design has successfully met our needs for Application level settings without having to do anything special during build, or modifying the Settings file for each application derived from the common base.

History

  • 2011/10/05: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Clifford Nelson Consulting
United States United States
Has been working as a C# developer on contract for the last several years, including 3 years at Microsoft. Previously worked with Visual Basic and Microsoft Access VBA, and have developed code for Word, Excel and Outlook. Started working with WPF in 2007 when part of the Microsoft WPF team. For the last eight years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with BioNano Genomics in San Diego, CA redesigning their UI for their camera system. he can be reached at qck1@hotmail.com.

Comments and Discussions

 
GeneralMy vote of 1 Pin
foczyduo30-Aug-13 0:22
foczyduo30-Aug-13 0:22 
AnswerRe: My vote of 1 Pin
Clifford Nelson30-Aug-13 6:36
Clifford Nelson30-Aug-13 6:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.