Repository navigation
Plugin UI Notifications and Themes
await context.UiManager.ShowNotificationAsync(
Info.PluginIdentifier,
new PluginNotificationRequest("Schedule refreshed", "42 events were loaded.", PluginNotificationSeverity.Success),
cancellationToken);Use Information for neutral state, Success for completed user actions, and Error for actionable failures. Avoid showing a notification for high-frequency background events; log those instead.
bool confirmed = await context.UiManager.ShowConfirmationAsync(
Info.PluginIdentifier,
"Clear cached schedule?",
"The schedule will be downloaded again the next time it is needed.",
cancellationToken);Use confirmation only for destructive or difficult-to-reverse actions.
UserControl content = new ScheduleDetailsView { DataContext = viewModel };
await context.UiManager.ShowDialogAsync(
Info.PluginIdentifier,
new PluginDialogRequest("Schedule Details", content, Width: 760, Height: 560),
cancellationToken);Plugin dialogs are owned, modeless windows. The main window remains interactive. The host closes registered plugin dialogs during plugin cleanup.
Named main-page elements currently include:
| Name | Type/purpose |
|---|---|
MainViewRoot |
Main view root grid |
ApplicationToolbar |
Top application toolbar |
ApplicationToolbarActions |
Toolbar button host |
ReceiverList |
Receiver list |
ReceiverWorkspace |
Workspace scroll viewer |
ReceiverWorkspaceGrid |
Main receiver content grid |
ReceiverInformationCard |
Receiver information card |
NowPlayingCard |
Now-playing card |
NowPlayingEventName |
Event title text |
NowPlayingEventTime |
Event time text |
NowPlayingProgressBar |
Live event progress |
NowPlayingOptionsHost |
Preferred host for compact now-playing options |
ChannelControlCard |
Channel-control card |
ReceiverActionsCard |
Receiver-actions card |
Named elements are extension points, not permanent child-index contracts. Handle null and application upgrades gracefully.
StackPanel? host = await context.UiManager.FindElementAsync<StackPanel>(
Info.PluginIdentifier,
"NowPlayingOptionsHost",
cancellationToken);
if (host is not null)
{
CheckBox option = new() { Content = "Use plugin schedule for now playing" };
option.SetResourceReference(FrameworkElement.StyleProperty, "ModernCheckBoxStyle");
host.Children.Add(option);
context.UiManager.RegisterCleanup(Info.PluginIdentifier, () => host.Children.Remove(option));
}For arbitrary main-window work:
await context.UiManager.InvokeOnMainWindowAsync(Info.PluginIdentifier, window =>
{
window.Activate();
}, cancellationToken);Register cleanup immediately after insertion, not later:
panel.Children.Add(card);
context.UiManager.RegisterCleanup(Info.PluginIdentifier, () =>
{
card.DataContext = null;
panel.Children.Remove(card);
});Also unsubscribe events owned by the control or view model. Host removal from the visual tree does not automatically detach external event subscriptions.
Apply styles with dynamic lookup:
button.SetResourceReference(FrameworkElement.StyleProperty, "PrimaryButtonStyle");| Resource | Target/use |
|---|---|
CardBorderStyle |
Standard card Border
|
PrimaryButtonStyle |
Accent primary action |
SecondaryButtonStyle |
Neutral secondary action |
SuccessButtonStyle |
Positive action |
DangerButtonStyle |
Destructive action |
IconButtonStyle |
Compact icon-only button |
TransparentButtonStyle |
Low-emphasis action |
ModernTextBoxStyle |
Text input |
ModernComboBoxStyle |
Single-choice input |
ModernCheckBoxStyle |
Checkbox |
ModernToggleSwitchStyle |
Toggle represented by a CheckBox
|
ModernContextMenuStyle |
Context menu |
ModernMenuItemStyle |
Context-menu item |
ModernMenuSeparatorStyle |
Menu separator |
PluginDataGridStyle |
Themed schedule/data grid |
ReceiverListBoxStyle / ReceiverListBoxItemStyle
|
Receiver-like lists |
PageTitleTextStyle |
Page title |
SectionTitleTextStyle |
Card/section title |
LabelTextStyle |
Uppercase field label |
ValueTextStyle |
Display value |
Styles used internally for plugin-manager cards, notifications, or discovery state may exist but are less stable extension points. Prefer the general-purpose resources above.
<Border Style="{DynamicResource CardBorderStyle}">
<StackPanel>
<TextBlock Text="Plugin Schedule" Style="{DynamicResource SectionTitleTextStyle}" />
<TextBlock Text="Current program" Foreground="{DynamicResource SecondaryTextBrush}" />
<Button Content="Refresh" Style="{DynamicResource SecondaryButtonStyle}" />
</StackPanel>
</Border>Use DynamicResource, not StaticResource, for theme colors and styles that should update while the application is running.