Skip to main content
.NET 8.0+

DevExpress v24.2 Update — Your Feedback Matters

Our What's New in v24.2 webpage includes product-specific surveys. Your response to our survey questions will help us measure product satisfaction for features released in this major update and help us refine our plans for our next major release.

Take the survey Not interested

How to: Display a List of Non-Persistent Objects with an Intermediate Container Class and Its Detail View

  • 4 minutes to read

This example stores a list of books. When a user clicks the Show Duplicate Books action, a pop-up dialog displays a list of duplicate books and their copy counts. This list is implemented as a non-persistent object‘s Detail View.

Book duplicates in a dialog popup

This example uses an intermediate container class to display a list of non-persistent objects. In this case, the ObjectsGetting method cannot be applied. If your application logic does not require complex operations to create non-persistent objects, use the ObjectsGetting method. Refer to the following help topic for implementation details: How to: Display a Non-Persistent Object's List View from the Navigation.

Tip

You can find the complete example in the following GitHub repository: How to: Display a List of Non-Persistent Objects with an Intermediate Container Class and Its Detail View.

The following steps include the key implementation points:

#Step 1: Declare the Book Persistent Class

Objects of this class denote books in a collection.

using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl.EF;

namespace NonPersistentListView.Module {
    [DefaultClassOptions]
    public class Book : BaseObject {
        public virtual string Title { get; set; }
    }
}

#Step 2: Declare Non-Persistent Classes

Declare two non-persistent classes—Duplicate and DuplicatesList, and decorate them with the DomainComponentAttribute.

  • The Duplicate class includes two properties—Title and Count. A class instance stores a unique book title and the total number of books with this title (if there is more than one book).
  • The DuplicatesList class aggregates the Duplicate objects.
using System.ComponentModel;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp;

namespace NonPersistentListView.Module {
    [DomainComponent]
    public class Duplicate: NonPersistentLiteObject {
        public string Title { get; set; }
        public int Count { get; set; }
    }
    [DomainComponent]
    public class DuplicatesList: NonPersistentLiteObject {
        private BindingList<Duplicate> duplicates;
        public DuplicatesList() {
            duplicates = new BindingList<Duplicate>();
        }
        public BindingList<Duplicate> Duplicates { get { return duplicates; } }
    }
}

Note

The INotifyPropertyChanged, IXafEntityObject and IObjectSpaceLink interface implementations were omitted in this example. However, it is recommended to support these interfaces in real-world applications (see The Importance of Property Change Notifications for Automatic UI Updates and Non-Persistent Objects).

#Step 3: Register the Non-Persistent Object Space Provider

Ensure that the Non-Persistent Object Space Provider is registered in the Application Builder code. The Solution Wizard adds this code automatically.

// ...
builder.ObjectSpaceProviders
    // ...
    .AddNonPersistent();
// ...

#Step 4: Count the Number of Book Copies

Create the ShowDuplicateBooksController View Controller. In the controller, implement a method that iterates through persistent Book objects and counts the number of copies of each book. Store this information in a dictionary.

// ...
private Dictionary<string, int> GetDuplicatesDictionary() {
    var dictionary = new Dictionary<string, int>();
    foreach(Book book in View.CollectionSource.List) {
        if(string.IsNullOrWhiteSpace(book.Title)) continue;
        dictionary[book.Title] = dictionary.GetValueOrDefault(book.Title) + 1;
    }
    return dictionary;
}
// ...

#Step 5: Create a List of Duplicate Objects

Implement a method that iterates through dictionary items and creates Duplicate objects for items with a value greater than one (books with more than one copy). Add Duplicate objects into a DuplicatesList collection.

// ...
private DuplicatesList CreateDuplicatesList(Dictionary<string, int> duplicatesDictionary, IObjectSpace objectSpace) {
    DuplicatesList duplicatesList = objectSpace.CreateObject<DuplicatesList>();
    foreach(var (title, count) in duplicatesDictionary) {
        if(count <= 1) continue;

        var duplicate = objectSpace.CreateObject<Duplicate>();
        duplicate.Title = title;
        duplicate.Count = count;
        duplicatesList.Duplicates.Add(duplicate);
    }
    objectSpace.CommitChanges();
    return duplicatesList;
}
// ...

#Step 6: Add PopupWindowShowAction

Add the PopupWindowShowAction to display a popup dialog when a user clicks the Show Duplicate Books action. Handle the CustomizePopupWindowParams event and call the CreateDetailView(IObjectSpace, Object) method to create a Detail View for the DuplicatesList object.

// ...
public ShowDuplicateBooksController() {
    PopupWindowShowAction showDuplicatesAction = new PopupWindowShowAction(this, "ShowDuplicateBooks", PredefinedCategory.View);
    showDuplicatesAction.CustomizePopupWindowParams += showDuplicatesAction_CustomizePopupWindowParams;
}
private void showDuplicatesAction_CustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e) {
    var duplicatesDictionary = GetDuplicatesDictionary();
    var nonPersistentObjectSpace = Application.CreateObjectSpace<DuplicatesList>();
    var duplicatesList = CreateDuplicatesList(duplicatesDictionary, nonPersistentObjectSpace);
    e.View = Application.CreateDetailView(nonPersistentObjectSpace, duplicatesList);
    e.DialogController.SaveOnAccept = false;
    e.DialogController.CancelAction.Active["NothingToCancel"] = false;
}
// ...
Show complete ShowDuplicateBooksController.cs code
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.Persistent.Base;
using System.Collections;

namespace NonPersistentListView.Module {
    public class ShowDuplicateBooksController : ObjectViewController<ListView, Book> {
        public ShowDuplicateBooksController() {
            PopupWindowShowAction showDuplicatesAction = new PopupWindowShowAction(this, "ShowDuplicateBooks", PredefinedCategory.View);
            showDuplicatesAction.CustomizePopupWindowParams += showDuplicatesAction_CustomizePopupWindowParams;
        }
        private void showDuplicatesAction_CustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e) {
            var duplicatesDictionary = GetDuplicatesDictionary();
            var nonPersistentObjectSpace = Application.CreateObjectSpace<DuplicatesList>();
            var duplicatesList = CreateDuplicatesList(duplicatesDictionary, nonPersistentObjectSpace);
            e.View = Application.CreateDetailView(nonPersistentObjectSpace, duplicatesList);
            e.DialogController.SaveOnAccept = false;
            e.DialogController.CancelAction.Active["NothingToCancel"] = false;
        }
        private Dictionary<string, int> GetDuplicatesDictionary() {
            var dictionary = new Dictionary<string, int>();
            foreach(Book book in View.CollectionSource.List) {
                if(string.IsNullOrWhiteSpace(book.Title)) continue;
                if(dictionary.TryGetValue(book.Title, out int count)) {
                    dictionary[book.Title] = count + 1;
                } else {
                    dictionary[book.Title] = 1;
                }
            }
            return dictionary;
        }
        private DuplicatesList CreateDuplicatesList(Dictionary<string, int> duplicatesDictionary, IObjectSpace objectSpace) {
            DuplicatesList duplicatesList = objectSpace.CreateObject<DuplicatesList>();
            foreach(var (title, count) in duplicatesDictionary) {
                if(count <= 1) continue;
                var duplicate = objectSpace.CreateObject<Duplicate>();
                duplicate.Title = title;
                duplicate.Count = count;
                duplicatesList.Duplicates.Add(duplicate);
            }
            objectSpace.CommitChanges();
            return duplicatesList;
        }
    }
}

#Result

The following images illustrate the implemented Action and its popup window.

#Windows Forms Application

WinForms application: Non-persistent objects in a dialog popup

#Blazor Application

Blazor application: Non-persistent objects in a dialog popup