Skip to main content

How to: Implement Custom Context Navigation

  • 6 minutes to read

The Navigation System supports context navigation. You can track the process of creating navigation items in the navigation control and add custom navigation items. This topic demonstrates how to implement custom context navigation in your applications. A Window Controller will be implemented. This Controller will add the “Task-Based Help” child navigation items, each of which will contain items invoking Detail Views displaying various help documents.

ContextNavigationCustomHowTo

To implement the sample custom context navigation, perform the following steps.

  1. Define the HelpDocument business class. This is the class that will represent help documents.
  2. Implement a custom Window Controller. It will contain the custom context navigation logic that will handle the ShowNavigationItemController.NavigationItemCreated. The event handler must create a child navigation item titled “Task-Based Help” and its corresponding child nodes pointing to appropriate help documents. Note that each help document will be associated with a particular business class. And a created navigation item can point to a View of a business class that does not have associated documents. In this instance, the “Task-Based Help” navigation item should not be created.

Define the HelpDocument Business Class

The HelpDocument business class is comprised of three properties.

  • Title - represents a document’s title.
  • Text - holds the actual text contained in the document. A help document’s text can be very long, so this property should be decorated with the Size[-1] attribute (see Data Annotations in Data Model).
  • ObjectType - each document will be associated with a business class. So only help topics relevant to a specific business class will be displayed. The ObjectType property holds the associated business class’ type. Since this property is of the Type type, a custom value converter must be implemented (see ValueConverter) for the property to be stored properly in the database.
using DevExpress.ExpressApp.Utils;
using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
// ...

public class ApplicationDbContext : DbContext {
    // ...
    public DbSet<HelpDocument> HelpDocuments { get; set;}
    // ...
    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        // ...
        modelBuilder.Entity<HelpDocument>()
            .Property(t => t.ObjectType)
            .HasConversion(new TypeToStringConverter());
    }
}

public class TypeToStringConverter : ValueConverter<Type, string> {
    public TypeToStringConverter() : base(
            v => v.FullName,
            v => ReflectionHelper.FindType(v)) { }
}

[DefaultClassOptions, ImageName("BO_Report")]
public class HelpDocument : BaseObject {
    public virtual Type ObjectType { get; set; }
    public virtual string Title { get; set; }
    [FieldSize(-1)]
    public virtual string Text { get; set; }
}

// Make sure that you use options.UseChangeTrackingProxies() in your DbContext settings.

Implement a Custom Window Controller

The custom Controller must only be activated for the main Window, since only main Window Templates contain the navigation Action Container (see Navigation System). To implement the custom context navigation logic, subscribe to the ShowNavigationItemController‘s NavigationItemCreated event. Do not forget to unsubscribe from the event to prevent memory leaks.

using DevExpress.ExpressApp.SystemModule;
//...
public class TaskBasedHelpController : WindowController {
    private ShowNavigationItemController navigationController;
    protected override void OnFrameAssigned() {
        UnsubscribeFromEvents();
        base.OnFrameAssigned();
        navigationController =
            Frame.GetController<ShowNavigationItemController>();
        if(navigationController != null) {
            navigationController.NavigationItemCreated += 
                navigationItemCreated;
        }
    }
    private void UnsubscribeFromEvents() {
        if(navigationController != null) {
            navigationController.NavigationItemCreated -= 
                navigationItemCreated;
            navigationController = null;
        }
    }
    protected override void Dispose(bool disposing) {
        UnsubscribeFromEvents();
        base.Dispose(disposing);
    }
}

Handle the NavigationItemCreated event

The NavigationItemCreated event occurs after a navigation item has been created in the navigation control. You will need to track the creation of navigation items in the event handler. Since not every navigation item points to a View, check whether a particular NavigationItem node’s View property is set. If it is, check whether help documents for a particular business class exist. If there are existing help documents, create the “Task-Based Help” child navigation item and populate it with child nodes corresponding to these existing help documents. Additionally, create a read-only HelpDocument_DetailView_FewColumns Detail View via the Model Editor. This View will be used to display help documents.

using System.Collections.Generic;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Model;
//...
public class TaskBasedHelpController : WindowController {
    //...
    void navigationItemCreated(object sender, NavigationItemCreatedEventArgs e) {
        ChoiceActionItem navigationItem = e.NavigationItem;
        IModelObjectView viewNode = ((IModelNavigationItem)e.NavigationItem.Model).View as 
            IModelObjectView;
        if (viewNode != null) {
            ITypeInfo objectTypeInfo = XafTypesInfo.Instance.FindTypeInfo(viewNode.ModelClass.Name);
            if (objectTypeInfo != null) {
                CriteriaOperator docCriteria = 
                    CriteriaOperator.Parse("ObjectType == ?", objectTypeInfo.Type);
                IObjectSpace myObjectSpace = Application.CreateObjectSpace(typeof(HelpDocument));
                IList<HelpDocument> docs = myObjectSpace.GetObjects<HelpDocument>(docCriteria);
                if (docs.Count > 0) {
                    ChoiceActionItem docsGroup = new ChoiceActionItem(
                        "CustomDocuments", "Task-Based Help", null) { ImageName = "BO_Report" };
                    navigationItem.Items.Add(docsGroup);
                    foreach (HelpDocument doc in docs) {
                        ViewShortcut shortcut = new ViewShortcut(typeof(HelpDocument), 
                            doc.Oid.ToString(), "HelpDocument_DetailView_FewColumns");
                        ChoiceActionItem docItem = new ChoiceActionItem(
                            doc.Oid.ToString(), doc.Title, shortcut) 
                            { ImageName = "Navigation_Item_Report" };
                        docsGroup.Items.Add(docItem);
                    }
                }
            }
        }
    }
}
See Also