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

Using the class

Using the class is extremely simple. Just declare a new class that derives from ModelBase and you are ready to go:

/// <summary>
/// MyObject class which fully supports serialization,
/// property changed notifications, backwards compatibility and error checking.
/// </summary>
public class MyObject : ModelBase<MyObject>
    /// <summary>
    /// Initializes a new object from scratch.
    /// </summary>
    public MyObject() { }

/// <summary>
/// Initializes a new object based on <see cref="SerializationInfo"/>.
/// </summary>
/// <param name="info"><see cref="SerializationInfo"/>
//     that contains the information.</param>
/// <param name="context"><see cref="StreamingContext"/>.</param>
protected MyObject(SerializationInfo info, StreamingContext context)
    : base(info, context) { }

As you can see in the code above, the MyObject class derives from ModelBase and provides an empty constructor, but also a constructor that is used for binary deserialization. The code above might look complex, but it is created using the model code snippet, and you only have to type the name of the class.

Defining properties

Defining properties for the class is very easy, and works the same like dependency properties. The advantages of this way of defining properties are:

Below is the code that defines a new property Name of type string:

/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name
    get { return GetValue<string>(NameProperty); }
    set { SetValue(NameProperty, value); }

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

A registered property can be excluded from serialization if wanted. When the object is deserialized, the default value will be used for the property in that case.

Default values for reference types

In lots of cases, a default value for reference types is required in the property definitions. However, and you might have noticed this behavior in for example dependency properties, using an instance as default value can result in unexpected behavior.

Below is an example of a “regular” property registration using a default value for a collection property:

public static readonly PropertyData NameProperty = RegisterProperty("PersonCollection", typeof(Collection<Person>), new Collection<Person>());

However, instead of creating a new collection for each new object with this property, only one collection will be created that will be used by all classes that have this property registered. One solution is to pass null as default value and create the collection in the constructor. A better solution is to use the override of RegisterProperty with the callback parameters:

public static readonly PropertyData NameProperty = RegisterProperty("PersonCollection", typeof(Collection<Person>), () => new Collection<Person>());

This way, every time a new value is needed, the callback will be invoked to create the default value and you will have a true default value for reference types.

Functionality provided out of the box

The ModelBase provides a lot of functionality out of the box. A few points I want to mention are:


All properties registered using the RegisterProperty method automatically take care of change notifications.


The data object can automatically create an internal backup and restore it, if required, using the IEditableObject interface.


As told many times before, using the [SavableModelBase](/5.2/catel-core/data-handling/savablemodelbase/), you can simply save your file to a stream (file on disk, stream in memory, etc.).

Keep in mind that this class is not suitable for database communication, there are much better ways to handle this (ORM mappers such as Entity Framework, NHibernate, LLBLGen Pro, etc.).

Have a question about Catel? Use StackOverflow with the Catel tag!