Follow @PDSAInc Binding to Config Settings in WPF - Paul Sheriff's Blog for the Real World

Paul Sheriff's Blog for the Real World

This blog is to share my tips and tricks garnered over 25+ years in the IT industry

Paul's Favorites

Binding to Config Settings in WPF

Almost every application has a configuration file used to store global settings. What would be cool is to have a global settings class that reads this data from the .Config file, then can be used to bind to UI elements within your WPF application. This is actually very easy to accomplish using the data-binding features in WPF.

Creating a Config Class

Below is a sample App.Config file you might add to a WPF application with a couple of settings in the <appSettings> element in the file.

<configuration>
  <appSettings>
    <add key="DefaultState" value="CA"/>
    <add key="IsActiveFlag" value="true"/>
  </appSettings>
</configuration>

These two values might be used as defaults to feed UI elements in your WPF application. So, you now need to create a class that will read these values from the .Config file. Below is a class named MySettings that has two properties; DefaultState and IsActiveFlag. In each of the Get methods is a call to the ConfigurationManager.AppSettings property to retrieve the appropriate element from the .Config file.

C#
public class MySettings
{
  public MySettings()
  {
  }

  public string DefaultState
  {
    get {
      return ConfigurationManager.AppSettings
              ["DefaultState"].ToString();
    }
  }

  public bool IsActiveFlag
  {
    get {
      return Convert.ToBoolean(ConfigurationManager.AppSettings
               ["IsActiveFlag"]);
    }
  }

  public void Refresh()
  {
    ConfigurationManager.RefreshSection("appSettings");
  }
}

Visual Basic
Public Class MySettings
  Public ReadOnly Property DefaultState() As String
    Get
      Return
        ConfigurationManager.AppSettings("DefaultState").ToString()
    End Get
  End Property

  Public ReadOnly Property IsActiveFlag() As Boolean
    Get
      Return Convert.ToBoolean( _
          ConfigurationManager.AppSettings("IsActiveFlag"))
    End Get
  End Property

  Public Sub Refresh()
    ConfigurationManager.RefreshSection("appSettings")
  End Sub
End Class

Now, you need to create an instance of this class in your WPF application and bind each property to a UI element.

Create Instance of Config Settings Class

Open your App.xaml or Application.xaml file and add a new namespace at the top that references your Namespace or application name. In my sample, I created a WPF application called WPFBindConfigSettings, so that is the name that I need to reference as shown in the code below.

<Application x:Class="WPFBindConfigSettings.App"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:src="clr-namespace:WPFBindConfigSettings"
 StartupUri="frmBindSettings.xaml">
  <Application.Resources>
    <ObjectDataProvider x:Key="odpSettings"
                        ObjectType="{x:Type src:MySettings}" />
  </Application.Resources>
</Application>

In the <Application.Resources> element you will add a <ObjectDataProvider> element that will create an instance of your MySettings class. As you can see in the above code that this is as simple as setting the ObjectType attribute in the ObjectDataProvider to src:MySettings. Set the  Key attribute for this ObjectDataProvider object to “odpSettings” as you will need to reference this resource from any window you create in your WPF application.

Bind to WPF UI

Now, let’s use this ObjectDataProvider to bind the values from the MySettings class to UI elements on a WPF Window as shown in Figure 1.

Binding to UI
Figure 1: You can bind settings from a Config

Below is the XAML to create the form shown in Figure 1.

<Grid>
  <StackPanel>
    <StackPanel Orientation="Horizontal">
      <Label>Default State</Label>
      <TextBox Name="txtDefaultState"
               Width="50"
               Text="{Binding Source={StaticResource odpSettings},
                      Path=DefaultState, Mode=OneWay}">
      </TextBox>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
      <Label>Is Active Flag?</Label>
      <CheckBox Name="chkIsActiveFlag"
                IsChecked="{Binding Source={StaticResource
                             odpSettings}, Path=IsActiveFlag,
                             Mode=OneWay}"
                VerticalAlignment="Center">
      </CheckBox>
    </StackPanel>
    <Button Name="btnRefresh"
            Click="btnRefresh_Click">Refresh</Button>
  </StackPanel>
</Grid>

In the above code you use the {Binding} syntax to read the values from the resource named “odpSettings” which is the Key value you created for the ObjectDataProvider in the App.xaml file. You must set the Mode=OneWay since the properties are read-only in the MySettings class. That is all there is to binding to the settings contained in the .Config file.

Refreshing the Config Settings

If you modify the values in the .Config file you will want to refresh the values in the ObjectDataProvider and ultimately in the UI. This can be easily accomplished with just a little bit of VB or C# code. Notice the Refresh method in the MySettings class presented above. The Refresh method in the MySettings class calls the ConfigurationManager.RefreshSection method to re-read a section in a .Config file. After refreshing the values from the .Config file you will want to have the UI be updated as well. You can accomplish this in a few different ways.

  1. Refresh each individual control (this approach takes the most code)
  2. Refresh the ObjectDataProvider which automatically refreshes the controls
  3. Implement the INotifyPropertyChanged interface. This is the best method to use

Let’s now take a look at each of these three approaches.

Refresh Each Individual Control

The first method is to refresh each individual control after calling the Refresh method on the MySettings class. This involves getting a reference to the MySettings instance in the ObjectDataProvider class. You can retrieve an instance of the ObjectDataProvider by calling the FindResource method on an instance of the current application. This is done in the source code shown in the following listing. Once you have the reference to the ObjectDataProvider you can grab an instance of the MySettings class and call the Refresh method on that object. This will cause the class to refresh the settings from the changed .Config file.

C#
private void RefreshControls()
{
  MySettings opts = (MySettings)((ObjectDataProvider)
      Application.Current.
          FindResource("odpSettings")).ObjectInstance;

  opts.Refresh();

  txtDefaultState.GetBindingExpression(
      TextBox.TextProperty).UpdateTarget();
  chkIsActiveFlag.GetBindingExpression(
      CheckBox.IsCheckedProperty).UpdateTarget();
}

Visual Basic
Private Sub RefreshControls()
  Dim opts As MySettings = DirectCast(DirectCast( _
        Application.Current.FindResource("odpSettings"), _
           ObjectDataProvider).ObjectInstance, MySettings)

  opts.Refresh()

  txtDefaultState.GetBindingExpression( _
     TextBox.TextProperty).UpdateTarget()
  chkIsActiveFlag.GetBindingExpression( _
     CheckBox.IsCheckedProperty).UpdateTarget()
End Sub

Next, you can update the target of the bindings of each control by using the GetBindingExpression method on the specific property on the control and then calling the UpdateTarget method on that property. This will force the control to refresh its binding.

Refresh the Data Provider

The second method you can use to refresh the data on the UI is to tell the ObjectDataProvider object to call its Refresh method. Again you need to get the instance of the ObjectDataProvider from the Application.Current property and call its FindResource method. You then get a reference to the MySettings object and call its Refresh method. Next, call the Refresh method on the ObjectDataProvider instance. This automatically refreshes all UI elements that are bound to this ObjectDataProvider.

C#
private void RefreshDataProvider()
{
  ObjectDataProvider dp =
  (ObjectDataProvider)Application.Current.
       FindResource("odpSettings");
  MySettings opts = (MySettings)dp.ObjectInstance;

  opts.Refresh();

  dp.Refresh();
}

Visual Basic
Private Sub RefreshDataProvider()
  Dim dp As ObjectDataProvider = _
    DirectCast(Application.Current.FindResource("odpSettings"), _
      ObjectDataProvider)
  Dim opts As MySettings = DirectCast(dp.ObjectInstance, _
      MySettings)

  opts.Refresh()

  dp.Refresh()
End Sub

Implement INotifyPropertyChanged

The third method you can use to refresh the data on the UI is to implement the INotifyPropertyChanged event on the MySettings class. When you implement this interface, you write code that will inform any data bindings that the property, or properties, on a class have changed.

You will modify the MySettings class in order to implement this interface. First off, you will need to import the System.ComponentModel namespace.

C#
using System.ComponentModel;

Visual Basic
Imports System.ComponentModel

Next, change the class definition to implement the interface.

C#
public class MySettings : INotifyPropertyChanged

Visual Basic
Public Class MySettings
  Implements INotifyPropertyChanged

Next you declare your intention to use the PropertyChangedEventHandler event procedure. To make it easier to call this from within the class, it is a good idea to create a method to raise this event. Below is code that needs to be added to the MySettings class.

C#
public event PropertyChangedEventHandler PropertyChanged;

protected void RaisePropertyChanged(string propertyName)
{
  var handler = PropertyChanged;
  if (handler != null)   {
    handler(this, new PropertyChangedEventArgs(propertyName));
  }
}       

Visual Basic
Public Event PropertyChanged(ByVal sender As Object, _
  ByVal e As System.ComponentModel.PropertyChangedEventArgs)  _
  Implements System.ComponentModel. _
               INotifyPropertyChanged.PropertyChanged

Protected Sub RaisePropertyChanged(ByVal propertyName As String)
  RaiseEvent PropertyChanged(Me, _
    New PropertyChangedEventArgs(propertyName))
End Sub

The code above takes care of notifying all bound objects about any changes to any properties in this class. Of course, it is up to you from within the class to call the RaisePropertyChanged method anytime you change the values from within the class. This means you need to change the Refresh method in the MySettings class to call the RaisePropertyChanged method.

C#
public void Refresh()
{
  ConfigurationManager.RefreshSection("appSettings");

  RaisePropertyChanged("DefaultState");
  RaisePropertyChanged("IsActiveFlag");
}

Visual Basic
Public Sub Refresh()
  ConfigurationManager.RefreshSection("appSettings")

  RaisePropertyChanged("DefaultState")
  RaisePropertyChanged("IsActiveFlag")
End Sub

The lines in bold are used to raise the PropertyChanged event so all bound objects to these properties are notified. Now you can call the following method in the Refresh button’s click event procedure in the WPF window.

C#
private void RefreshINotify()
{
  MySettings opts = (MySettings)((ObjectDataProvider)
   Application.Current.FindResource("odpSettings")).ObjectInstance;

  opts.Refresh();
}

Visual Basic
Private Sub RefreshINotify()
  Dim opts As MySettings = _
    DirectCast(DirectCast( _
      Application.Current.FindResource("odpSettings"), _
      ObjectDataProvider).ObjectInstance, MySettings)

  opts.Refresh()
End Sub

If you now run this sample and modify the .Config file and click the Refresh button, you will see the change made.

Summary

The data binding features of WPF are useful for more than just binding to database data. In this article you discovered how you can use the binding features to bind .Config file data to UI elements and how to refresh that data when the .Config file changes. You should use the INotifyPropertyChanged interface in most of the classes you create as this will make data binding to UI notifications almost automatic.

Download the Complete Sample

We have the completed sample for this article available on our website at http://www.pdsa.com/Downloads. Once there, select “Tips and Tricks” from the Category drop-down. Then select “WPF Sample – Bind Config Settings” from the Item drop-down.

Good Luck With Your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".

Posted: Oct 19 2009, 10:49 PM by psheriff | with 1 comment(s)
Filed under: ,

Comments

Carlos said:

Great article!!!. I downloaded your sample and worked very good and I adapted in my project and worked too.

Thank you so much.

# June 2, 2010 10:47 AM