-
Notifications
You must be signed in to change notification settings - Fork 6
workspace sdk tiles
Tile extensions add custom functionality to Security Desk's tile-based monitoring interface. The Workspace SDK provides three complementary component types for extending tiles: widgets for the right-side controls panel, views for content inside tiles, and properties for configuration tabs.
Use a tile extension when you need to react to the currently selected tile by adding side-panel controls, in-tile visuals, or bottom configuration tabs that depend on the tile's current content.
- Your module creates one or more tile component builders and registers them with
Workspace.Components. - Security Desk evaluates each builder against the current
TilePluginContextby callingIsSupported(...). - When a builder supports the current tile context, the framework creates the tile widget, tile view, or tile properties instance through
CreateView(). - The framework calls
Update(...)when the selected tile, content group, or current content changes. - Your component updates its UI based on the current tile context.
- When the module unloads, it unregisters the builders.
Security Desk displays content in tiles arranged on tile pages. Each tile has a TileState that contains the current ContentGroup, which usually exposes the active Content through its Current property. Tile extensions respond to changes in this hierarchy through the shared TilePluginContext.
Alarm and event tiles are a special case. AlarmContent and EventContent derive from SourceContent, which itself derives from ContentGroup. For those tile types, inspect context.ContentGroup to access the alarm or event metadata.
All tile components receive a TilePluginContext that provides access to the current tile state:
| Member | Type | Description |
|---|---|---|
Page |
TilePage | The active tile page |
TileState |
TileState | The selected tile's state |
ContentGroup |
ContentGroup | Content group displayed in the tile |
Content |
Content | Current content within the group |
Use these properties in your IsSupported method to determine whether your component applies to the current tile content.
Tile widgets appear in Security Desk's right-side controls panel, stacked below built-in widgets like camera playback controls, PTZ controls, or door status. When you select a tile, widgets registered for that content type appear in the controls panel. Use them to display supplementary information or controls related to the tile's content.
Create a builder class that inherits from TileWidgetBuilder:
public class MyTileWidgetBuilder : TileWidgetBuilder
{
public override string Name => "My Tile Widget";
public override Guid UniqueId => new Guid("...");
public override string Title => "Widget Title";
public override int Priority => 100;
public override bool IsSupported(TilePluginContext context)
{
return context.Content is VideoContent;
}
public override TileWidget CreateView()
{
return new MyTileWidget();
}
}| Member | Type | Description |
|---|---|---|
Name |
string | Component display name |
UniqueId |
Guid | Unique component identifier |
Title |
string | Widget header displayed in the controls panel |
Priority |
int | Display order (lower values appear first) |
IsSupported(TilePluginContext) |
bool | Return true when the widget applies |
CreateView() |
TileWidget | Factory method to create the widget |
Implement the widget view by inheriting from TileWidget:
public class MyTileWidget : TileWidget
{
private readonly MyWidgetControl m_control = new MyWidgetControl();
public override UIElement View => m_control;
protected override void OnContentChanged()
{
m_control.UpdateDisplay(Content);
}
}| Member | Type | Description |
|---|---|---|
View |
UIElement | The widget's visual content |
Page |
TilePage | Current tile page (read-only) |
TileState |
TileState | Current tile state (read-only) |
ContentGroup |
ContentGroup | Current content group (read-only) |
Content |
Content | Current content (read-only) |
Update(TilePluginContext) |
void | Called by the framework to update the widget's context |
The TileWidget automatically synchronizes its properties when Update is called. The TileState property is set from the context, which triggers ContentGroup to update from TileState.Content, which in turn updates Content from ContentGroup.Current. This cascading update fires the corresponding lifecycle callbacks.
TileWidget provides virtual methods that fire when the tile context changes:
| Method | Invoked when |
|---|---|
OnPageChanged() |
The tile page changes |
OnTileStateChanged() |
The tile state changes |
OnContentGroupChanged() |
The content group changes |
OnContentChanged() |
The content changes |
Override these methods to update your widget's display when the tile content changes.
Tile views render custom content directly inside the tile area itself. When you select a tile displaying supported content, tile views appear within the tile's visual space. Use them to display custom entity visualizations, overlays, or annotations on top of or instead of the default content.
Create a builder that inherits from TileViewBuilder:
public class MyTileViewBuilder : TileViewBuilder
{
public override string Name => "My Tile View";
public override Guid UniqueId => new Guid("...");
public override int Priority => 100;
public override bool IsSupported(TilePluginContext context)
{
return context.Content is VideoContent;
}
public override TileView CreateView()
{
return new MyTileView();
}
}| Member | Type | Description |
|---|---|---|
Name |
string | Component display name |
UniqueId |
Guid | Unique component identifier |
Priority |
int | Display order (lower values appear first) |
IsSupported(TilePluginContext) |
bool | Return true when the view applies |
CreateView() |
TileView | Factory method to create the view |
Implement the view by inheriting from TileView:
public class MyTileView : TileView
{
private readonly MyOverlayControl m_overlay = new MyOverlayControl();
public MyTileView()
{
Placement = Placement.OverVideo;
}
public override UIElement View => m_overlay;
public override void Update(TilePluginContext context)
{
m_overlay.UpdateOverlay(context.Content);
}
}| Member | Type | Description |
|---|---|---|
View |
UIElement | The view's visual content |
Placement |
Placement | Where the view appears in the tile |
Update(TilePluginContext) |
void | Called when the tile context changes |
The Placement property controls where the view appears within the tile:
| Value | Description |
|---|---|
Normal |
Constrained below the tile toolbar (default) |
Extended |
Full tile area below the toolbar |
OverVideo |
Overlaid on top of video content |
Tile properties add custom tabs to the bottom of Security Desk's right-side controls panel, alongside the built-in "General" tab. When you select a tile displaying supported content, your custom tab appears and provides configuration options specific to that content type.
Create a builder that inherits from TilePropertiesBuilder:
public class MyTilePropertiesBuilder : TilePropertiesBuilder
{
public override string Name => "My Tile Properties";
public override Guid UniqueId => new Guid("...");
public override string Title => "My Settings";
public override int Priority => 100;
public override bool IsSupported(TilePluginContext context)
{
return context.Content is VideoContent;
}
public override TileProperties CreateView()
{
return new MyTileProperties();
}
}| Member | Type | Description |
|---|---|---|
Name |
string | Component display name |
UniqueId |
Guid | Unique component identifier |
Title |
string | Tab title displayed at the bottom of the controls panel |
Priority |
int | Tab order (lower values appear first) |
IsSupported(TilePluginContext) |
bool | Return true when the properties apply |
CreateView() |
TileProperties | Factory method to create the view |
Implement the properties view by inheriting from TileProperties:
public class MyTileProperties : TileProperties
{
private readonly MyPropertiesControl m_control = new MyPropertiesControl();
public override UIElement View => m_control;
public override void Update(TilePluginContext context)
{
m_control.LoadSettings(context.Content);
}
}| Member | Type | Description |
|---|---|---|
View |
UIElement | The properties panel content |
Update(TilePluginContext) |
void | Called when the tile context changes |
Important
Tile components require a valid SDK certificate.
Register tile components in your module's Load method and unregister them in Unload:
public class SampleModule : Module
{
private MyTileWidgetBuilder m_widgetBuilder;
private MyTileViewBuilder m_viewBuilder;
private MyTilePropertiesBuilder m_propertiesBuilder;
public override void Load()
{
m_widgetBuilder = new MyTileWidgetBuilder();
m_widgetBuilder.Initialize(Workspace);
Workspace.Components.Register(m_widgetBuilder);
m_viewBuilder = new MyTileViewBuilder();
m_viewBuilder.Initialize(Workspace);
Workspace.Components.Register(m_viewBuilder);
m_propertiesBuilder = new MyTilePropertiesBuilder();
m_propertiesBuilder.Initialize(Workspace);
Workspace.Components.Register(m_propertiesBuilder);
}
public override void Unload()
{
if (m_widgetBuilder != null)
{
Workspace.Components.Unregister(m_widgetBuilder);
m_widgetBuilder = null;
}
if (m_viewBuilder != null)
{
Workspace.Components.Unregister(m_viewBuilder);
m_viewBuilder = null;
}
if (m_propertiesBuilder != null)
{
Workspace.Components.Unregister(m_propertiesBuilder);
m_propertiesBuilder = null;
}
}
}The IsSupported method determines when your tile component appears. To implement this method effectively, you need to understand how Security Desk organizes content within tiles.
Tiles organize content in a hierarchy:
TilePage
└── TileState (one per tile)
└── ContentGroup (what the tile displays)
└── Content[] (one or more content items)
└── Current (the active content)
| Class | Description |
|---|---|
TileState |
Represents a tile's state, including selection and content |
ContentGroup |
A collection of content items displayed in a tile |
Content |
A single displayable item within a content group |
A ContentGroup contains one or more Content objects. When a content group has multiple items, Security Desk can cycle through them automatically (content rotation).
| Member | Type | Description |
|---|---|---|
Contents |
ObservableCollection<Content> | All content items in the group |
Current |
Content | The currently visible content |
Title |
string | Display title for the group |
Icon |
ImageSource | Display icon for the group |
| Event | Description |
|---|---|
CurrentChanged |
Fires when the active content changes (cycling) |
Content is the base class for the displayable item exposed through context.Content. Security Center also provides specialized content groups for source-driven tiles such as alarms and events.
| Type | Base | Description |
|---|---|---|
EntityContent |
Content | Generic entity display (has EntityId) |
VideoContent |
EntityContent | Camera video with playback controls |
MapContent |
EntityContent | Map display with zoom and center |
WebContent |
Content | Web page display (has Url) |
AlarmContent |
SourceContent (ContentGroup) |
Alarm-focused content group with alarm metadata |
EventContent |
SourceContent (ContentGroup) |
Event-focused content group with event metadata |
VideoContent is the most common content type. It provides rich video control:
| Member | Type | Description |
|---|---|---|
EntityId |
Guid | The camera's entity identifier |
VideoMode |
VideoMode | Live or Playback mode |
State |
VideoState | Current video state (Playing, Paused, etc.) |
VideoTime |
DateTime | Current playback timestamp |
CurrentTime |
DateTime | Timeline position |
EntityContentGroup is a specialized content group for displaying entities:
var group = new EntityContentGroup(cameraGuid);
group.Initialize(Workspace);The IsSupported method receives a TilePluginContext and returns whether your component should appear. Check both the ContentGroup and its Current content.
Check the current content type directly in IsSupported:
public override bool IsSupported(TilePluginContext context)
{
return context.Content is VideoContent;
}Inspect the current content and then resolve the entity when needed:
public override bool IsSupported(TilePluginContext context)
{
if (context.Content is VideoContent video)
{
var camera = Workspace.Sdk.GetEntity(video.EntityId) as Camera;
return camera?.IsOnline == true;
}
return false;
}When you need to know about all content in the tile, not just the current item:
public override bool IsSupported(TilePluginContext context)
{
var group = context.ContentGroup;
if (group == null)
{
return false;
}
return group.Contents.Any(c => c is VideoContent);
}public override bool IsSupported(TilePluginContext context)
{
return context.Content is VideoContent
|| context.Content is MapContent
|| context.ContentGroup is AlarmContent
|| context.ContentGroup is EventContent;
}Tile widgets receive lifecycle callbacks when the content hierarchy changes:
| Method | When called |
|---|---|
OnContentChanged() |
The current Content changes |
OnContentGroupChanged() |
The entire ContentGroup changes |
OnTileStateChanged() |
The TileState changes |
OnPageChanged() |
The TilePage changes |
Override these methods to update your widget when the user switches content or navigates to a different tile:
protected override void OnContentChanged()
{
if (Content is VideoContent video)
{
m_control.ShowVideoInfo(video.EntityId, video.VideoMode);
}
else
{
m_control.ClearDisplay();
}
}- Overview
- Connecting to Security Center
- SDK certificates
- Referencing SDK assemblies
- SDK compatibility
- Entities
- Entity cache
- Transactions
- Events
- Actions
- Security Desk
- Custom events
- ReportManager
- ReportManager query reference
- DownloadAllRelatedData and StrictResults
- Privileges
- Partitions
- Logging
- Overview
- Certificates
- Lifecycle
- Threading
- State management
- Configuration
- Restricted configuration
- Events
- Queries
- Request manager
- Database
- Entity ownership
- Entity mappings
- Server management
- Custom privileges
- Custom entity types
- Resolving non-SDK assemblies
- Deploying plugins
- .NET 8 support
- Overview
- Certificates
- Creating modules
- Tasks
- Pages
- Components
- Tile extensions
- Services
- Contextual actions
- Options extensions
- Configuration pages
- Monitors
- Shared components
- Commands
- Extending events
- Map extensions
- Timeline providers
- Image extractors
- Credential encoders
- Credential readers
- Cardholder fields extractors
- Badge printers
- Content builders
- Dashboard widgets
- Incidents
- Logon providers
- Pinnable content builders
- Custom report pages
- Overview
- Getting started
- MediaPlayer
- VideoSourceFilter
- MediaExporter
- MediaFile
- G64 converters
- FileCryptingManager
- PlaybackSequenceQuerier
- PlaybackStreamReader
- OverlayFactory
- PtzCoordinatesManager
- AudioTransmitter
- AudioRecorder
- AnalogMonitorController
- Camera blocking
- Overview
- Getting started
- Referencing entities
- Entity operations
- About access control in the Web SDK
- About video in the Web SDK
- Users and user groups
- Partitions
- Custom fields
- Custom card formats
- Actions
- Events and alarms
- Incidents
- Reports
- Tasks
- Macros
- Custom entity types
- System endpoints
- Performance guide
- Reference
- Under the hood
- Troubleshooting