Click here to Skip to main content
15,867,488 members
Articles / Desktop Programming / WPF
Article

WPF Control State Persistency

Rate me:
Please Sign up or sign in to vote.
4.61/5 (11 votes)
9 Jun 20073 min read 123.7K   651   37   32
This article describes how to store and restore WPF's elements state, such as position, size, etc.

Introduction

Someone asked me if WPF provides an option for storing or serializing control state. For an instance, having a ListView, is it possible to store the width of its columns after closing and opening the Window, or maybe after restarting the application?

I was thinking to myself, sure, you should use Data Binding. All you have to do is to bind the width or height, of any element to a back storage. For example you can create a State class for storing the data, and then you should bind it to your properties, using the Binding markup extension.

Thinking twice, I realized that it is much more complicated than it looks. Data Binding is a great tool but it should be customized to support this feature.

So the answer was no! but...

Then I developed a smart Markup Extension, backed up with Attached Properties and a smart Back Storage to provide an easy way to save controls properties state.

Using the code

To work with the attached code, you should:

  • Add a reference to the Tomers.WPF.State.dll assembly (unless you have compiled it with a different name)
  • Mark each persist-element with a unique ID (among the whole application) by using the ElementState.UId attached property
  • Select the state mode by using the ElementState.Mode attached property
  • Provide a value to any element property by using the ElementState Markup Extension

NOTE: I'm using the XmlnsDefinitionAttribute attribute for mapping the CLR namespace into the WPF XML root namespace, so you don't need to use any prefix for using these custom types from XAML.

The markup snippet below demonstrates how to use my Markup Extension and Attached Properties to store a Window Size and Position, and a ListView, GridViewColumn's width.

XML
<Window x:Class="Tomers.WPF.State.Demo.DemoWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:data="clr-namespace:Tomers.WPF.State.Demo.Data"

    ElementState.Mode="Persist"
    ElementState.UId="DemoWindow"
    Height="{ElementState Default=300}"
    Width="{ElementState Default=300}"
    Left="{ElementState Default=100}"
    Top="{ElementState Default=100}"

    Title="Test">

    <Window.Resources>
        <ObjectDataProvider x:Key="cConsultants" 
            ObjectType="{x:Type data:Consultants}" />
    </Window.Resources>

    <StackPanel>
      <ListView ItemsSource="{Binding Source={StaticResource cConsultants}}">
        <ListView.View>
            <GridView ColumnHeaderToolTip="Sela Consultants">
               <GridViewColumn
                  ElementState.Mode="Persist"
                  ElementState.UId="DemoWindow_GridViewColumn1"
                  DisplayMemberBinding="{Binding Path=FirstName}"
                  Header="First Name"
                  Width="{ElementState Default=100}" />
               <GridViewColumn
                  ElementState.Mode="Persist"
                  ElementState.UId="DemoWindow_GridViewColumn2"
                  DisplayMemberBinding="{Binding Path=LastName}"
                  Header="Last Name"
                  Width="{ElementState Default=100}" />
               <GridViewColumn
                  ElementState.Mode="Persist"
                  ElementState.UId="DemoWindow_GridViewColumn3"
                  DisplayMemberBinding="{Binding Path=Blog}"
                  Header="Blog"
                  Width="{ElementState Default=Auto}" />
            </GridView>
        </ListView.View>
      </ListView>
    </StackPanel>
</Window>

Using the Demo

Download the attached file, extract it into your local directory, and open the WPFElementState.sln solution file with Visual Studio 2005. Build and Run!

Now, resize the main window, move it to any place on the desktop, resize any grid column. Close the application, run it again! (The Window position and size, and columns width should be restored).

How it Works?

As you can see, I'm using the ElementState.Mode and ElementState.UId attached properties to tell the back storage to save the state for these element's dependency properties. Then I'm using the ElementState Markup Extension to set each property and its default value.


The ElementState.Mode attached property can be one of: Persist or Memory values.

  • Persist is used to serialize the element state into an XML stream. Restarting the application will restore this state.
  • Memory is used to hold the state only in memory. Restarting the application will not restore this state.

The ElementState.UId attached property is used to uniquely identify the element (this must be a unique name among all elements of the application).

To load and save state, you should call the ElementStateOperations.Load and ElementStateOperations.Save methods respectively. These methods accept any valid Stream instance, which should be readable or writeable stream respectively. This stream is used for serializing the state by using the XmlSerializer class. For example:

C#
public partial class App : System.Windows.Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        using (Stream stream = File.Open("ElementStateDemo.xml",
           FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read))
        {
            ElementStateOperations.Load(stream);
        }
        base.OnStartup(e);
    }

    protected override void OnExit(ExitEventArgs e)
    {
        using (Stream stream = File.Open("ElementStateDemo.xml",
           FileMode.Create, FileAccess.Write, FileShare.None))
        {
            ElementStateOperations.Save(stream);
        }
        base.OnExit(e);
    }
}

Points of Interest

It is a first prototype, it took me several hours to write it down, so use it at your own risk.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Architect CodeValue
Israel Israel
Tomer Shamam is a Software Architect and a UI Expert at CodeValue, the home of software experts, based in Israel (http://codevalue.net). Tomer is a speaker in Microsoft conferences and user groups, and in-house courses. Tomer has years of experience in software development, he holds a B.A degree in computer science, and his writings appear regularly in the Israeli MSDN Pulse, and other popular developer web sites such as CodePlex and The Code Project. About his thoughts and ideas you can read in his blog (http://blogs.microsoft.co.il/blogs/tomershamam).

Comments and Discussions

 
QuestionGreat, but not Working (VS2019) Pin
apoplex200813-Dec-21 22:59
apoplex200813-Dec-21 22:59 
QuestionProblem with VS2010 XAML designer Pin
lbrodny4-Jul-12 23:49
lbrodny4-Jul-12 23:49 
AnswerRe: Problem with VS2010 XAML designer Pin
lbrodny28-Aug-12 21:53
lbrodny28-Aug-12 21:53 
QuestionHandling Bound columns? Pin
colkaih26-Nov-08 4:58
colkaih26-Nov-08 4:58 
GeneralGlobalization problem Pin
yoavo23-Sep-08 1:31
yoavo23-Sep-08 1:31 
QuestionThe demo is never runing with vs2008? Pin
wangfeng00721-Sep-08 17:02
wangfeng00721-Sep-08 17:02 
AnswerRe: The demo is never runing with vs2008? Pin
Tomer Shamam21-Sep-08 20:56
Tomer Shamam21-Sep-08 20:56 
GeneralSave order of the columns Pin
yoavo26-Aug-08 21:18
yoavo26-Aug-08 21:18 
GeneralRe: Save order of the columns Pin
Tomer Shamam30-Aug-08 2:09
Tomer Shamam30-Aug-08 2:09 
QuestionRead XAML file Pin
Krishnraj18-Jul-08 21:53
Krishnraj18-Jul-08 21:53 
AnswerRe: Read XAML file Pin
Tomer Shamam19-Jul-08 19:50
Tomer Shamam19-Jul-08 19:50 
GeneralRe: Read XAML file Pin
Krishnraj20-Jul-08 19:05
Krishnraj20-Jul-08 19:05 
GeneralRe: Read XAML file Pin
Krishnraj20-Jul-08 21:46
Krishnraj20-Jul-08 21:46 
GeneralRe: Read XAML file Pin
Tomer Shamam22-Jul-08 11:02
Tomer Shamam22-Jul-08 11:02 
QuestionNRE Setting Attached Property on Markup Extension in XAML Pin
RobbyMon15-Jul-08 10:59
RobbyMon15-Jul-08 10:59 
AnswerRe: NRE Setting Attached Property on Markup Extension in XAML Pin
Tomer Shamam15-Jul-08 20:41
Tomer Shamam15-Jul-08 20:41 
Hi Robert,

If I'm getting you right, you are trying to extract the value of an attached property, attached to the element on which the Markup Extension is applied?

If this is true. than try the following code, you will see that it is working, unless I didn't understand your need.

// TestExtension.cs
namespace WindowsApplication1
{
public class TestExtension : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
IProvideValueTarget provideValue = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (provideValue == null)
{
throw new NotSupportedException("The IProvideValueTarget is not supported");
}
DependencyObject target = (DependencyObject)provideValue.TargetObject;
DependencyProperty property = (DependencyProperty)provideValue.TargetProperty;

double top = Canvas.GetTop(target as UIElement);

return "OK";
}
}
}


<!-- Window1.xaml -->
<Window x:Class="WindowsApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WindowsApplication1"
Title="WindowsApplication1" Height="300" Width="300">

<Canvas>
<Button x:Name="_button"
Content="{local:Test}"
Canvas.Top="10"
Click="button_Click" />
</Canvas>
</Window>


Cheers!
GeneralRe: NRE Setting Attached Property on Markup Extension in XAML Pin
RobbyMon16-Jul-08 3:12
RobbyMon16-Jul-08 3:12 
GeneralRe: NRE Setting Attached Property on Markup Extension in XAML Pin
Tomer Shamam16-Jul-08 3:17
Tomer Shamam16-Jul-08 3:17 
GeneralRe: NRE Setting Attached Property on Markup Extension in XAML Pin
Tomer Shamam16-Jul-08 3:29
Tomer Shamam16-Jul-08 3:29 
GeneralRe: NRE Setting Attached Property on Markup Extension in XAML Pin
RobbyMon16-Jul-08 4:17
RobbyMon16-Jul-08 4:17 
GeneralRe: NRE Setting Attached Property on Markup Extension in XAML Pin
Tomer Shamam16-Jul-08 5:50
Tomer Shamam16-Jul-08 5:50 
GeneralRe: NRE Setting Attached Property on Markup Extension in XAML Pin
RobbyMon16-Jul-08 10:50
RobbyMon16-Jul-08 10:50 
GeneralFixed version Pin
sungwoo park19-Jun-08 15:04
sungwoo park19-Jun-08 15:04 
GeneralUpdate ProvideValue routine Pin
klange2-Jun-08 12:30
klange2-Jun-08 12:30 
QuestionVisual Studio 2008 RTM Designer Pin
yohoohoy22-Nov-07 8:03
yohoohoy22-Nov-07 8:03 

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.