Non-Persistent Objects

A non-persistent class is a type of business class. XAF generates a UI for this class but does not bind it to an application's database table. You can use this class to display a List or Detail View with temporary data generated in code or loaded from storage. You can also use it to display an empty View (dialog) and process the user's input.

Important Notes

Basic Non-Persistent Class Implementation

Declare a regular class in the module project and decorate it with the DomainComponentAttribute to implement a non-persistent class.

using DevExpress.ExpressApp.DC;
// ...
[DomainComponent]
public class MyNonPersistentObject {
    public string Name { get; set; }
    public string Description { get; set; }
}

XAF automatically registers the class with this attribute in the Types Info Subsystem and adds it to the Application Model. Rebuild the solution and open the Model Editor to ensure that XAF added the class to the BOModel node and created the corresponding List and Detail Views.

NonPersistentObjectModel

XAF can display this MyNonPersistentObject's Detail View in a PopupWindowShowAction's popup dialog (see the Add an Action that Displays a Pop-up Window topic).

MyNonPersistentObjectPopup

You can also use the ActionAttribute to show a non-persistent object's popup. For this purpose, apply this attribute to a business class' method that takes a non-persistent type parameter.

Examples:

Non-Persistent Object Space

NonPersistentObjectSpace is an Object Space used to manage non-persistent object instances in your application. You can create, read, or update non-persistent object instances from code if the XafApplication object supports this Object Space type. To support this Object Space type, add the following code to the overridden CreateDefaultObjectSpaceProvider method in the WinApplication.cs (WinApplication.vb), WebApplication.cs (WebApplication.vb), and/or MobileApplication.cs (MobileApplication.vb) file (in addition to the existing XPObjectSpaceProvider or EFObjectSpaceProvider registration).

protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) {
    // ...
    args.ObjectSpaceProviders.Add(new NonPersistentObjectSpaceProvider(TypesInfo, null));
}

Note that the Solution Wizard adds the code above automatically.

XAF uses the first registered Object Space Provider for the following purposes:

Ensure that NonPersistentObjectSpaceProvider is not the first registered Provider in your application.

IMPORTANT

NonPersistentObjectSpace cannot handle persistent objects. To process these objects, create an additional Object Space for the persistent object type and add it to the NonPersistentObjectSpace.AdditionalObjectSpaces collection. Refer to the How to: Show Persistent Objects in a Non-Persistent Object's View topic for more information.

Also, note that you may need to refresh and dispose of Object Spaces from this collection simultaneously with the parent non-persistent Object Space. To do this automatically, use the following properties and fields:

Use the CreateObjectSpace(Type) method to create an Object Space and manage non-persistent objects in your code (for example, in the Controller's code):

using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
// ...
public class ShowDetailViewController : ViewController<ListView> {
    // ...
    void showDetailViewAction_CustomizePopupWindowParams(
        object sender, CustomizePopupWindowParamsEventArgs e) {
        IObjectSpace newObjectSpace = Application.CreateObjectSpace(typeof(NonPersistentObject));
        // ...
    }
}

When you create a NonPersistentObjectSpace instance in a Controller (for example, to show a custom dialog), you can customize it in the Controller's code.

Handle the XafApplication.ObjectSpaceCreated event to specify default settings for all NonPersistentObjectSpaces in your application and subscribe to their events. You can do this in a Module after application setup is completed.

using System;
using DevExpress.ExpressApp;
//...
public sealed partial class MyModule : ModuleBase {
    //...
    public override void Setup(XafApplication application) {
        base.Setup(application);
        application.SetupComplete += Application_SetupComplete;
    }
    private void Application_SetupComplete(object sender, EventArgs e) {
        Application.ObjectSpaceCreated += Application_ObjectSpaceCreated;
    }
    private void Application_ObjectSpaceCreated(object sender, ObjectSpaceCreatedEventArgs e) {
        NonPersistentObjectSpace nonPersistentObjectSpace = e.ObjectSpace as NonPersistentObjectSpace;
        if(nonPersistentObjectSpace != null) {
            // Subscribe to NonPersistentObjectSpace events and customize its properties
        }
    }
}
NOTE

We do not recommend that you subscribe to the XafApplication.ObjectSpaceCreated event from a View or Window Controller. This may lead to multiple event invocations, because Controllers are created for each Frame. For example, a Window Controller that targets the main window can be instantiated and activated multiple times when you use it in a WinForms application with UIType = TabbedMDI mode or a WebForms application with EnableMultipleBrowserTabsSupport = true.

To supply data to non-persistent objects, handle the following NonPersistentObjectSpace events raised when the Object Space loads non-persistent objects:

Since these events are raised to request any non-persistent object (declared in custom or built-in Modules), check the object type passed in event parameters before modifying the events' output parameters.

You can use the New, Delete, and Save Actions to manipulate non-persistent objects. The NonPersistentObjectSpace.ModifiedObjects collection contains all modified objects. Newly created and deleted objects are added to this collection automatically. To add an existing object to this collection, use the IObjectSpace.SetModified(Object) method. If an object implements the INotifyPropertyChanged interface, you can set AutoSetModifiedOnObjectChange or AutoSetModifiedOnObjectChangeByDefault to true to add this object to the ModifiedObjects collection automatically when its property is changed.

Examples

Key Property

In XAF ASP.NET and Mobile applications, business objects need a key property to be correctly displayed in List Views.

In ASP.NET applications, each ASPxGridView control's row must have a unique key. This key is required for select, filter, sort and group operations and the standard XAF functionality that depends on them. A key property is also required when you handle the NonPersistentObjectSpace.ObjectByKeyGetting event.

In Mobile applications, the key value is included in requests sent by a client application to receive a non-persistent object (for example, when showing a Detail View from a List View). Handle the NonPersistentObjectSpace.ObjectByKeyGetting event to pass an appropriate object to the client application.

Use the KeyAttribute to declare a key property. The BrowsableAttribute allows you to hide this property from UI. The following code snippet demonstrates how to declare the key property in the non-persistent class:

[DomainComponent]
public class NonPersistentObject {
    [Browsable(false)]
    [DevExpress.ExpressApp.Data.Key]
    public int Oid { get; set; }
    // ...
}
IMPORTANT

Use the Key attribute from the DevExpress.ExpressApp.Data namespace only (not from the System.ComponentModel.DataAnnotations or DevExpress.Xpo namespaces).

You can allow users to open a specific non-persistent object instance from the Navigation:

  1. Add an item to the navigation. Set its IModelNavigationItem.View property to the identifier of the non-persistent object's DetailView and the IModelNavigationItem.ObjectKey to an arbitrary integer value.

    NonPersistentKey

  2. Subscribe to the NonPersistentObjectSpace.ObjectByKeyGetting event handler. Find an object instance whose type matches the event's e.ObjectType parameter and the key value coincides with the e.Key parameter. Pass this object to the event's e.Object parameter.

Example: How to: Display a Non-Persistent Object's Detail View from the Navigation

Filter and Sort Non-Persistent Objects

You can use the DevExpress.ExpressApp.DynamicCollection to filter and sort a collection of non-persistent objects. Follow the steps below to do this.

  1. Handle the NonPersistentObjectSpace.ObjectsGetting event.
  2. In this event handler, create a new DynamicCollection and subscribe to its FetchObjects event. This event raises after sort or filter parameters are changed.
  3. Pass a list of non-persistent objects to the Objects event argument. You can filter and sort this list based on event arguments; to do this automatically, set the ShapeData argument to true.
  4. Pass the DynamicCollection instance to the NonPersistentObjectSpace.ObjectsGetting Objects argument.

The following code demonstrates how you can implement it in your application.

using System;
using System.Collections.Generic;
using DevExpress.ExpressApp;
// ...
public sealed partial class NonPersistentObjectsDemoModule : ModuleBase {
    private List<Contact> contacts;
    // ...
    public override void Setup(XafApplication application) {
        base.Setup(application);
        application.SetupComplete += Application_SetupComplete;
    }
    private void Application_SetupComplete(object sender, EventArgs e) {
        Application.ObjectSpaceCreated += Application_ObjectSpaceCreated;
    }
    private void Application_ObjectSpaceCreated(object sender, ObjectSpaceCreatedEventArgs e) {
        NonPersistentObjectSpace nonPersistentObjectSpace = e.ObjectSpace as NonPersistentObjectSpace;
        if (nonPersistentObjectSpace != null) {
            nonPersistentObjectSpace.ObjectsGetting += ObjectSpace_ObjectsGetting;
        }
    }
    private void ObjectSpace_ObjectsGetting(object sender, ObjectsGettingEventArgs e) {
        if (e.ObjectType == typeof(Contact)) {
            DynamicCollection collection = new DynamicCollection((IObjectSpace)sender, e.ObjectType, e.Criteria, e.Sorting, e.InTransaction);
            collection.FetchObjects += DynamicCollection_FetchObjects;
            e.Objects = collection;
        }
    }
    private void DynamicCollection_FetchObjects(object sender, FetchObjectsEventArgs e) {
        if (e.ObjectType == typeof(Contact)) {
            e.Objects = contacts; // your collection of non-persistent objects.
            e.ShapeData = true; // set to true if the supplied collection is not already filtered and sorted.
        }
    }
}

Refer to the How to filter and sort Non-Persistent Objects GitHub repository to see the full example.

INotifyPropertyChanged Support

Implement the INotifyPropertyChanged interface in your non-persistent class to use XAF features that track and process property value changes (for example, Conditional Appearance). Call the OnPropertyChanged method from the property's setter to trigger the PropertyChanged event. The Object Space handles this event internally. The PropertyChanged event triggers the IObjectSpace.ObjectChanged event.

Example: How to: Perform CRUD Operations with Non-Persistent Objects | PropertyChanged Event in Business Classes

IXafEntityObject and IObjectSpaceLink Support

Implement the IXafEntityObject interface to add custom business logic to the non-persistent class code. This interface declares methods that are called when the Object Space creates, loads, or saves an object. You can also implement the IObjectSpaceLink interface and use the Object Space the IObjectSpaceLink.ObjectSpace property returns. This allows you to query other objects in the same Object Space.

using DevExpress.ExpressApp;
// ...
[DomainComponent]
public class MyNonPersistentObject : IXafEntityObject, IObjectSpaceLink{
    // ...
    void IXafEntityObject.OnCreated() {
        // Place the entity initialization code here.
        // You can initialize reference properties using Object Space methods; e.g.:
        // this.Address = objectSpace.CreateObject<Address>();
    }
    void IXafEntityObject.OnLoaded() {
        // Place the code that is executed each time the entity is loaded here.
    }
    void IXafEntityObject.OnSaving() {
        // Place the code that is executed each time the entity is saved here.
    }
    IObjectSpace IObjectSpaceLink.ObjectSpace {
        get { return objectSpace; }
        set { objectSpace = value; }
    }
}

Example: How to: Perform CRUD Operations with Non-Persistent Objects

Non-Persistent Object Template

You can use a Visual Studio template to create a non-persistent class. For this purpose, open the Template Gallery, switch to the XAF category and choose the XAF Business Object | Non-Persistent Object item. The added class can be used in different complex scenarios listed in this topic.

NonPersistentObjectTemplate

This non-persistent class includes the IXafEntityObject, IObjectSpaceLink and INotifyPropertyChanged interface implementations and an integer type key property.

See Also