Skip to content

workspace sdk pages

Andre Lafleur edited this page Oct 8, 2026 · 12 revisions

About pages

Pages provide UI content displayed in a monitor. Each page occupies one tab in a monitor and has its own lifecycle, from initialization through activation, deactivation, and disposal. Pages are typically opened by tasks but can also be created and added to monitors programmatically.

Use a page when your extension needs a full monitor tab with its own WPF view, lifecycle, and persisted state rather than a smaller UI component such as a widget, options page, or contextual action.

How pages work

  1. The module creates a page instance and calls Initialize(Workspace) to set up the page
  2. If the client is connected and the page is not a ConfigPage or ReportPage, Initialize(Workspace) validates the SDK certificate, prepares the page, then calls the protected Initialize() method where you assign the View
  3. The page is added to a monitor's PageCollection through Monitor.Pages.Add(page)
  4. When the page becomes the active tab, the framework calls OnActivated(Monitor)
  5. When the page loses focus to another tab, the framework calls OnDeactivated(Monitor)
  6. When the workspace saves, the framework calls Serialize() to persist the page state
  7. When the workspace restores, the framework calls Deserialize(byte[]) to restore the page state
  8. When the page is closed, the framework calls Dispose() if the page implements IDisposable

Important

Standard Page subclasses require a valid SDK certificate when they initialize against a connected system. ConfigPage and ReportPage are exceptions with their own lifecycle rules.

Page

Create a page by inheriting from Genetec.Sdk.Workspace.Pages.Page. Set the View property to a WPF UserControl that defines the page content:

public class MyPage : Genetec.Sdk.Workspace.Pages.Page
{
    protected override void Initialize()
    {
        View = new MyPageView();
    }
}

Page implements INotifyPropertyChanged and extends DependencyObject, so it is the view model for its view. Bind your view's controls directly to page properties and call OnPropertyChanged() to raise change notifications:

public class MyPage : Genetec.Sdk.Workspace.Pages.Page
{
    private string m_filter;

    public string Filter
    {
        get => m_filter;
        set { m_filter = value; OnPropertyChanged(nameof(Filter)); }
    }

    protected override void Initialize()
    {
        View = new MyPageView { DataContext = this };
    }
}

The SDK also provides TilePage, a Page subclass that adds tile layout management through its Pattern, States, and SynchronizeVideo properties. Use TilePage when the page itself needs a tile layout and tile-state collection.

Page properties

Member Type Description
Id Guid Unique page instance identifier.
Type Guid Page type identifier. Set automatically from the PageDescriptor when using PageAttribute.
Name string Display name shown on the page tab. Supports two-way data binding.
View UIElement The WPF content displayed when the page is active. Assign this in Initialize().
IsActive bool (readonly) Whether the page is currently the active tab on its monitor.
IsClosed bool (readonly) Whether the page has been closed.
Workspace Workspace The workspace instance. Available after Initialize(Workspace) is called.

Page lifecycle methods

Method Description
Initialize() Protected virtual. Override to set up the page and assign View. Called by the framework during Initialize(Workspace).
OnActivated(Monitor) Protected virtual. Called when the operator switches to this page's tab on a monitor. Also called when the page is first set as the active page.
OnDeactivated(Monitor) Protected virtual. Called when the operator switches away from this page's tab to another page on the same monitor.

To clean up resources when the page is closed, implement IDisposable on your page class. The framework checks for IDisposable and calls Dispose() when the page is removed.

public class MyPage : Genetec.Sdk.Workspace.Pages.Page, IDisposable
{
    protected override void Initialize()
    {
        View = new MyPageView();
    }

    protected override void OnActivated(Monitor monitor)
    {
        // Page became the active tab
    }

    protected override void OnDeactivated(Monitor monitor)
    {
        // Page is no longer the active tab
    }

    public void Dispose()
    {
        // Clean up event subscriptions
        // and other resources
    }
}

Page serialization

Operators can save the current workspace as a private or public configuration. Private configurations are stored per user in the Directory database. Public configurations are stored as shared entities accessible based on partition permissions.

When an operator saves a workspace, the framework calls Serialize() on each open page to capture its data. When the operator later loads that saved workspace, the framework recreates each page and calls Deserialize(byte[]) to restore it. Deserialize is only called when restoring from a saved workspace. It is not called when a page is opened for the first time.

Page-specific data includes anything the page needs to return to the same view the operator left: filter criteria, selected entities, sort order, text input, or display settings.

Override Serialize to return the page data as a byte array, and Deserialize to restore it. The serialization format is up to you. This example uses JSON:

public class SerializablePage : Genetec.Sdk.Workspace.Pages.Page
{
    private string m_filter;
    private Guid m_selectedEntityId;

    protected override void Initialize()
    {
        View = new MyPageView { DataContext = this };
    }

    protected override byte[] Serialize()
    {
        var state = new
        {
            Filter = m_filter,
            SelectedEntityId = m_selectedEntityId
        };

        string json = JsonSerializer.Serialize(state);
        return Encoding.UTF8.GetBytes(json);
    }

    protected override void Deserialize(byte[] data)
    {
        if (data == null)
            return;

        string json = Encoding.UTF8.GetString(data);

        var state = JsonSerializer.Deserialize<JsonElement>(json);

        m_filter = state.GetProperty("Filter").GetString();
        m_selectedEntityId = state.GetProperty("SelectedEntityId").GetGuid();
    }
}

Override CanSave() to control whether the page is included when saving the workspace. Returns true by default.

Page descriptors

A PageDescriptor provides metadata about a page type. The descriptor defines the name, icon, thumbnail, and category that appear on the home page without instantiating the page itself.

PageDescriptor properties

Member Type Description
Name string (abstract) Default page name displayed on the home page and tab header.
Type Guid (abstract) Unique page type identifier.
Description string (virtual) Page description. Defaults to empty.
CategoryId Guid (virtual) Task category for home page placement. Use a TaskCategories constant. Defaults to Guid.Empty.
Icon ImageSource (virtual) 16x16 icon shown in the tab header. The SDK provides a default if not set.
Thumbnail ImageSource (virtual) 256x256 image shown on the home page tile. The SDK provides a default if not set.
PositionIndex int (virtual) Sort priority on the home page (default 0).
AllowOfflineExecution bool (virtual) Whether the page is visible when disconnected from the server. Defaults to true.
IconColor TaskIconColor (virtual) Icon color displayed on the home page.

Task categories

The TaskCategories class provides constants for the built-in home page groups:

Constant Description
TaskCategories.Operation Operational monitoring tasks.
TaskCategories.Investigation Investigation and report tasks.
TaskCategories.Maintenance System maintenance tasks.
TaskCategories.Administration Administrative tasks.
TaskCategories.Diagnosis Diagnostic tasks.
public override Guid CategoryId => new Guid(TaskCategories.Investigation);

PageDescriptor methods

Method Description
HasPrivilege() Return true if the current user has permission to access this page type. Defaults to true. Override to restrict access based on user privileges.
Initialize(IEngine) Called by the framework during task initialization, before HasPrivilege() is ever called. After this call, the protected m_sdk field is available for privilege checks.

Restricting access with privileges

Override HasPrivilege() to hide the task from the home page when the current user lacks a required privilege. The m_sdk field is available because the framework calls Initialize(IEngine) before HasPrivilege():

public class MyPageDescriptor : PageDescriptor
{
    private static readonly Guid MyPrivilegeId = new Guid("11111111-1111-1111-1111-111111111111");

    public override string Name => "My Custom Page";
    public override Guid Type => new Guid("22222222-2222-2222-2222-222222222222");

    public override bool HasPrivilege()
    {
        return m_sdk.SecurityManager.IsPrivilegeGranted(MyPrivilegeId);
    }
}

When HasPrivilege() returns false, the CreatePageTask<T> reports that it cannot execute, and the home page hides the task.

Associating a descriptor with a page

Apply PageAttribute to your page class, passing the descriptor type. The descriptor must derive from PageDescriptor and have a public constructor with no parameters. The page view is a standard WPF UserControl.

<UserControl
    x:Class="MyModule.MyPageView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <StackPanel Margin="10">
    <TextBox x:Name="FilterTextBox" />
    <ListBox x:Name="EntityList" />
  </StackPanel>
</UserControl>
[Page(typeof(MyPageDescriptor))]
public class MyPage : Genetec.Sdk.Workspace.Pages.Page
{
    protected override void Initialize()
    {
        View = new MyPageView();
    }
}

public class MyPageDescriptor : PageDescriptor
{
    public override string Name => "My Custom Page";

    public override Guid Type => new Guid("22222222-2222-2222-2222-222222222222");

    public override Guid CategoryId => new Guid(TaskCategories.Operation);

    public override ImageSource Thumbnail => new BitmapImage(new Uri(@"pack://application:,,,/MY-ASSEMBLY;Component/Resources/MY-THUMBNAIL.png", UriKind.RelativeOrAbsolute));
}

CreatePageTask<T> reads the PageAttribute to extract the descriptor and use its metadata for the task's name, icon, thumbnail, category, and privilege check.

CreatePageTask

CreatePageTask<T> is a generic task that creates and opens a page of type T. This simplifies the common pattern of creating a task that opens a page:

public class SampleModule : Module
{
    private CreatePageTask<MyPage> m_task;

    public override void Load()
    {
        m_task = new CreatePageTask<MyPage>();
        m_task.Initialize(Workspace);
        Workspace.Tasks.Register(m_task);
    }

    public override void Unload()
    {
        if (m_task != null)
        {
            Workspace.Tasks.Unregister(m_task);
            m_task = null;
        }
    }
}

The page class must be public, have a public constructor with no parameters, and have a PageAttribute with a valid descriptor.

Singleton pages

By default, executing a CreatePageTask<T> creates a new page instance each time. To allow only one instance:

public CreatePageTask<MyPage> CreateSingletonTask()
{
    return new CreatePageTask<MyPage>(isSingleton: true);
}

When isSingleton is true, executing the task activates the existing page instead of creating a new one. If the page exists on a different monitor, it is moved to the active monitor.

CreatePageTask behavior

When executed, CreatePageTask<T>:

  1. For singleton pages, searches all monitors for an existing instance of type T
  2. If no existing page is found, creates a new instance using the parameterless constructor and calls Initialize(Workspace)
  3. Adds the page to the active monitor's page collection
  4. Sets the page as the active page on the monitor

Page collections

Each Monitor has a PageCollection accessible through Monitor.Pages:

Member Description
Add(Page) Add a page to the monitor.
Remove(Page) Remove a page from the monitor.
Contains(Page) Check if a specific page instance exists.
Contains(PageDescriptor) Check for a page whose PageAttribute descriptor has the same Type GUID as the supplied descriptor. Pages without PageAttribute are not matched.
Count The number of pages on the monitor.
this[int] Get a page by index.

Set Monitor.ActivePage to switch the active tab:

public void OpenPageOnActiveMonitor(Workspace workspace)
{
    var page = new MyPage();
    page.Initialize(workspace);
    workspace.ActiveMonitor.Pages.Add(page);
    workspace.ActiveMonitor.ActivePage = page;
}

See also

Platform SDK

Plugin SDK

Workspace SDK

Media SDK

Macro SDK

Web SDK

Synergis RIO

Media Gateway

Genetec Web Player

Clone this wiki locally