Managing application resources when WPF is hosted

Recently, I was working on a project that had WPF controls and windows hosted in Windows Media Player. When using WPF styles correctly (themes, resources, etc), normally one would create a resource library with all the styles.

When WPF is hosted, no System.Windows.Application.Current is available, so no application resources are available. Because of this, every window and control has to load the main theme resource dictionary on each load. This isn’t exactly what one would like to do. After searching for a while, I found this interesting article of Dr. WPF. It’s a long article, but the most interested part is to create the current application object yourself:

public static void EnsureApplicationResources()
{
    if (Application.Current == null)
    {
        // create the Application object
        new Application();

        // merge in your application resources
        Application.Current.Resources.MergedDictionaries.Add(
            Application.LoadComponent(
                new Uri("MyLibrary;component/Resources/MyResourceDictionary.xaml",
                UriKind.Relative)) as ResourceDictionary);
    }
}

At first, this seemed to work great in my scenario. However, when a window was shown the 2nd time, the application (in my case, Windows Media Player) crashed. After some investigation, I noticed that the application was not valid anymore after the the first window was shown. This brought me to the idea that the first window that is created is automatically set to the main window of the application. As soon as that window closes, the application gets destroyed. However, I don’t have a main window, I can only show windows as popups, not as main window of the application.

Hereby, I present to you as a reader of my blog, the solution to this issue. Create the first “main application window” yourself and make sure that it is invisible. This window will stay in scope (since Application.Current.MainWindow has a reference) as long as the hosting application is running. The following code should be used instead of the one that Dr. WPF has posted:

/// 
/// Ensures that an application instance exists and the styles are applied to the application.
/// 
public static void EnsureApplicationResources()
{
	// Do we have an application?
	if (Application.Current == null)
	{
		// Create the Application object
		new Application();

		// merge in your application resources
		Application.Current.Resources.MergedDictionaries.Add(Application.LoadComponent(new Uri("/MyLibrary;component/Themes/Generic.xaml", 
			UriKind.RelativeOrAbsolute)) as ResourceDictionary);

		// Create style forwarders
		CatenaLogic.Windows.StyleHelper.CreateStyleForwardersForDefaultStyles(Application.Current.Resources);

		// Create an invisible dummy window to make sure that this is the main window
		Window dummyMainWindow = new Window();
		dummyMainWindow.Visibility = Visibility.Hidden;
	}
}

As you might have noticed, a StyleHelper is used. This is another article, you can find it here.

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

DataObjectBase -> the new Object class for data objects!

Important update!!!

The code posted with this article is version 2.0.0. To downloaded the latest version, check out my article on The CodeProject.

 

Original article:

One of the problems every developer faces with is data persistence. Most software that is written requires the ability to save objects to disk, or serialize them (binary or XML) to use .NET remoting or web services. The .NET framework supports a lot of interfaces to implement this:

But, you also want to be notified when a property of the data object changes, and now you are writing this piece of software, you decide to implement data validation as well. The following .NET interfaces are required:

What happens is that you need to write a lot of (redundant) to support all these interfaces for all your data classes. Then you haven’t even thought of versioning in binary serialized objects that are really difficult to deal with. Also, when (de)serializing objects, you will find yourself write a lot of custom (repetitive) code which actually does the same and is very hard to maintain.

Table of contents

  1. Introduction
  2. Usage examples
  3. Explanation
  4. History
  5. Download

Introduction

Summary of DataObjectBase

The DataObjectBase class is a generic base class that can be used for all your data classes.

  1. Fully serializable
    It is now really easy to store the objects on disk or serialize them into memory, either binary or in XML. The data object supports this out of the box and automatically handles the (de)serialization.
  2. Support property changed notifications
    The class supports the INotifyPropertyChanged notifications so this class can easily be used in WPF and MVC applications to show error messages to the user.
  3. Backwards compatibility
    When serializating your objects binary, it is hard to maintain the right versions. When you add a new property to a binary class, or change a namespace, the object cannot be loaded any longer. The data object base takes care of this issue and supports backwards compatibility.
  4. Error checking
    The class implements IDataErrorInfo so it is possible to validate the data object and check the errors. This way, no custom validation code needs to be written outside the data class.
  5. Backup & revert
    The class implements the IEditableObject interface which makes it possible to create a state of the object. Then all properties can be edited, and finally the changes can be applied or canceled.

To support all this functionality out of the box, the class implements the following interfaces:

Interface Reason
ISerializable Required to make the object serializable.
INotifyPropertyChanged Required to notify other classes of property changes that occur inside the object.
IDataErrorInfo Required to notify other classes about errors in the data object. Very useful in WPF to show errors automatically in the user interface.
IDataWarningInfo Custom interface, similar to IDataErrorInfo, to support warnings in the data object.
IClonable Required to support cloning of the data object.
IEditableObject Required to create states in the data object. Therefore, it is possible to create a state before the user starts editing the object. Then, the changes can be confirmed or canceled.

Requirements

The requirements depend on whether support for collection changes is required. If so, .NET framework 3.0 is required. If not, .NET framework 2.0 is sufficient to use the class.

How to declare the class

The class requires a special declaration. The declaration seems like a lot of code, but a code snippet ‘dataobject’ is included in the package to easily create new objects.

/// <summary>
/// MyFirstObject Data object class which fully supports serialization, property changed notifications,
/// backwards compatibility and error checking.
/// </summary>
[Serializable]
public class MyFirstObject : DataObjectBase
{
    /// <summary>
    /// Initializes a new object from scratch.
    /// </summary>
    public MyFirstObject()
        : base() { }

    /// <summary>
    /// Initializes a new object based on .
    /// </summary>
    ///  that contains the information.
    /// .
    public MyFirstObject(SerializationInfo info, StreamingContext context)
        : base(info, context) { }
}

How to declare properties

A data class without properties is like a bike without wheels. You can sit on it, but you can never ride the thing. So, it is very important to declare properties. However, since the class uses a special (de)serialization of the properties, a special declaration is required.

To declare a property, use the included code snippet ‘propdata’.

/// <summary>
/// Gets or sets the value of MyFirstProperty.
/// </summary>
public string MyFirstProperty
{
	get { return GetValue(MyFirstPropertyProperty); }
	set { SetValue(MyFirstPropertyProperty, value); }
}

/// <summary>
/// Register the property so it is known in the class.
/// </summary>
public readonly PropertyData MyFirstPropertyProperty = RegisterProperty("MyFirstProperty", typeof(string), string.Empty);

As you can see, a special wrapper for the property is created that uses the GetValue and SetValue methods of the base class. The most important part of the property definition is the call to RegisterProperty. The first argument is the name of the property, the second argument is the type of the property, the third argument is the default value, in case the property is not yet available or cannot be deserialized.

Usage examples

All the examples listed below are available as code inside the downloadable package included in this article. Most of the examples have a real-life example which can be started to show that it actually works :)

Example 01 – Simple object

This example shows how to create a basic object that can be used as a “normal” CLR object:

/// <summary>
/// SimpleObject Data object class which fully supports serialization, property changed notifications,
/// backwards compatibility and error checking.
/// </summary>
[Serializable]
public class SimpleObject : DataObjectBase
{
    #region Variables
    #endregion

    #region Constructor & destructor
    /// <summary>
    /// Initializes a new object from scratch.
    /// </summary>
    public SimpleObject()
        : base() { }

    /// <summary>
    /// Initializes a new object based on .
    /// </summary>
    ///  that contains the information.
    /// .
    public SimpleObject(SerializationInfo info, StreamingContext context)
        : base(info, context) { }
    #endregion

    #region Properties
    /// <summary>
    /// Gets or sets the simple property.
    /// </summary>
    public string SimpleProperty
    {
        get { return GetValue(SimplePropertyProperty); }
        set { SetValue(SimplePropertyProperty, value); }
    }

    /// <summary>
    /// Register the property so it is known in the class.
    /// </summary>
    public readonly PropertyData SimplePropertyProperty = RegisterProperty("SimpleProperty", typeof(string), string.Empty);
    #endregion

    #region Methods
    #endregion
}

Example 02 – Error validation

This example shows how to implement validation into the object. Validation will prevent objects that are not valid to be stored (invalid objects cannot be serialized). This example shows an object using WPF, which can show the current errors in the object real-time to the end-user.

Objects have 2 types of validation results. There can either be errors that prevent the object from being serialized, and warnings, that are just warnings so the object can still be serialized.

To enable validation, you must override at least one of the following methods:

/// <summary>
/// Validates the fields.
/// </summary>
protected override void ValidateFields()
{
    // Validate for warnings
    if (string.IsNullOrEmpty(Recommended)) SetFieldWarning(RecommendedProperty, "The recommended property is missing!");

    // Validate for errors
    if (string.IsNullOrEmpty(Required)) SetFieldError(RequiredProperty, "The required property is missing!");
}

/// <summary>
/// Validates the business rules.
/// </summary>
protected override void ValidateBusinessRules()
{
    // Check for fields
    if (string.IsNullOrEmpty(Recommended) && string.IsNullOrEmpty(Required))
    {
        SetBusinessRuleError("A combination of field data is not valid, make sure to enter at least one field!");
    }
}

The validation in WPF will result in the following output:

Example 03 – Serialization

This example shows how to use the Save and Load methods to serialize/deserialize objects to/from disk. The object itself can also directly serialize/deserialize into memory, but this is not shown in the example.

To save an object, call the Save method on the object itself:

myObject.Save("MyFile.dob", SerializationMode.Binary);

To load an object, call the static Load method on the class to load:

SerializableObject myObject = SerializableObject.Load("MyFile.dob", SerializationMode.Binary);

Example 04 – Nested objects

The class is perfectly capable of nesting. This means that you can use objects, that are based on DataObjectBase, can contain other classes also based on DataObjectBase. This creates the ability to create parent/child objects where the whole tree is fully serializable. Nothing of interest to show here, just look into the example if you need more information on this topic.

Example 05 – Backward compatibility

This example shows how an “old” (standard .NET) data class that uses custom binary serialization can easily be converted to a DataObjectBase to use the DataObjectBase even for all your existing classes.

Declare a new DataObjectBase class (remember the ‘dataobject’ code snippet). If the new class is in a new assembly, or has a new name or namespace, use the RedirectType attribute to let the DataObjectBase know that when it finds the old type, it should deserialize that type into the new type.

Then, by default, the DataObjectBase class will try to deserialize the old object. If it fails to do so, it will fall back on the default values provided by the property declarations. However, it is also possible to override the GetDataFromSerializationInfo method:

/// <summary>
/// Retrieves the actual data from the serialization info.
/// </summary>
/// .
/// <remarks>
/// This method should only be implemented if backwards compatibility should be implemented for
/// a class that did not previously implement the DataObjectBase class.
/// </remarks>
protected override void GetDataFromSerializationInfo(SerializationInfo info)
{
    // Check if deserialization succeeded
    if (DeserializationSucceeded) return;

    // Deserialization did not succeed for any reason, so retrieve the values manually
    // Luckily there is a helper class (SerializationHelper) that eases the deserialization of "old" style objects
    FirstName = SerializationHelper.GetString(info, "FirstName", FirstNameProperty.GetDefaultValue());
    LastName = SerializationHelper.GetString(info, "LastName", LastNameProperty.GetDefaultValue());
}

Example 06 - Revert and apply

This example shows how to create a state for an object. This is extremely useful when an object is used in an edit mode. Just before the window is shown, a new state is created. Then, when the user clicks the OK button, the new state is applied. When the user clicks the Cancel button, the changes are cleared by reverting to the state created when the window just opened.

To create a state, use the following code:

myObject.BeginEdit();

To apply all changes made to the object since the last state, use the following code:

myObject.EndEdit();

To revert all changes made to the object since the last state, use the following code:

myObject.CancelEdit();

Explanation

How does it all work in the background? Well, the idea is pretty basic and simple, the way it is implemented is not because of the support for all the features and interfaces. The DataObjectBase class holds a dictionary of registered properties, and the current values for the properties. Then, the GetValue and SetValue methods can be used to get or set the values inside the dictionary.

The biggest issue (actually, it was a challenge, not an issue) was to deserialize all the data automatically, especially with different version numbers of assemblies or renamed types. When deserializing binary objects, the .NET framework is very, very strict and even the slightest change in the class or assembly will completely ruin the deserialization and thus the data of the user.

The DataObjectClass solves this in 2 ways. First of all, it checks for the RedirectType attribute to see if any types should be redirected to new types. Then, it initializes a custom SerializationBinder to redirect all the types. This solves the renaming of types, and can also take care of versioning of the types.

However, there are still problems left. When deserializing, you never know when your object (and its child objects) are completely deserialized. To solve this problem, the OnDeserialized attribute is implemented as well as the IDeserializationCallback interface. Using a single one of these will not solve the problem, but using both together has solved the problem.

History

2010/04/29 - First good release with real-life examples

Download

DataObjectBase.zip (235.26 kb) [Downloads: 117]

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

WPF “Tip of the Day” window

Sometimes, your end-users aren’t the smartest creatures on the planet. Lots of times, I am talking to an end-user because there is a “bug” or “critical issue” that needs to be fixed right away.

During the “debug” session (read: using the software as the end-user has described), you hit a lot of key strokes and other useful shortcuts that I thought the user was already familiar with. Unfortunately, most of the time, they are not.

Therefore, the Tip of the Day window is a great way of showing the end-user some handy tips when they start your software. For example, to learn about shortcuts, “hidden” features and more. The window of this post just does that:

tip_of_the_day

The window is really easy to use, you will just need to call the following code in the startup (or any location you like) of your software:

TipOfTheDayWindow tipOfTheDayWindow = new TipOfTheDayWindow();
if (tipOfTheDayWindow.HasTipsToShow)
{
    tipOfTheDayWindow.ShowDialog();
}

You must be thinking: why a blog post for such an easy window? Well, because this “Tip of the Day” window has much more features than you can see on first sight. For example, did you ever think on how to enter or manage the tips? Well, this window takes care of that for you.

Simply hit CTRL + F2 when the “Tip of the Day” window is focused, and you will see the following edit mode:

tip_of_the_day_editor

With the included editor, you can simply create, modify, remove and preview all the tips that are included with the window. The tips are stored in xml format in a subdirectory “Help”.

Don’t wait too long, start using the “Tip of the Day” window today!

TipOfTheDayWindow.zip (295.57 kb) [Downloads: 131]

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

WPF TraceOutputControl

Lately (actually, the last few years :)), I have been developing a lot of applications using WPF. One of the “nasty” things about WPF development is that binding errors are written to the output window, but that I currently have other windows open as well (and I don’t want the output window of Visual Studio to be open all of the time). Another drawback of the output window is that it does not support runtime filtering and clear feedback that an error has occurred (for example, in red).

I noticed that I was writing a quick and dirty output window for every project to be able to view the binding expression errors in the application itself. I also noticed that other developers were having the same issues and I decided to create a simple, ready-to-use, user control that supports output tracing with filtering.

Demo_screenshot

With this control, you can debug your application much easier and you will notice that an error or warning has occurred :). You can also decide to skip all the verbose output at runtime and simply filter on warning and errors only.

TraceOutputControl.zip (395.18 kb) [Downloads: 223]

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

DataWindow – Quickly create basic windows in WPF

When developing software in WPF, I always need the following three types of windows:

  • OK / Cancel buttons for data windows;
  • OK / Cancel / Apply buttons for application settings / options;
  • Close button on windows for action windows.

Creating these windows is just boring and the steps are always the same:

  1. Create a WrapPanel at the bottom of the window
  2. Add the buttons with the same RoutedUICommand objects over and over again

The attached class makes it much easier to create these basic windows, simply by specifying the mode of the Window. By using this window, you can concentrate on the actual implementation and you don’t have to worry about the implementation of the buttons itself, which saves you time!

DataWindow demo

Using the class is very easy. Simply derive the Window class from DataWindow instead of Window. The demo application should give you enough information on how to proceed.

20091203 - DataWindow.zip (342.70 kb) [Downloads: 237]

kick it on DotNetKicks.com 

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList