Class UIHost
- Namespace
- PluginUI
- Assembly
- PluginUI.dll
Hosts a tree of UIElements in a Win32 child window rendered with Direct2D. The same class serves plug-in editors (child of the DAW window) and standalone applications (child of a StandaloneWindow).
public sealed class UIHost : IDisposable
- Inheritance
-
UIHost
- Implements
- Inherited Members
Examples
A standalone application (in a plug-in, PluginEditorView creates and attaches the host):
StandaloneWindow.EnablePerMonitorDpiAwareness();
var root = new Canvas();
root.Add(new Knob(new LocalParameter("Drive", 0, 10, 2)) { Label = "DRIVE", Left = 20, Top = 20, Width = 72, Height = 96 });
var host = new UIHost(root, new Size(320, 200), SizingMode.ScaleToFit)
{
Theme = Theme.Dark.WithAccent(Color.FromRgb(0xFFB74D)),
MinSize = new Size(240, 150),
};
return new StandaloneWindow(host, "Drive").Run();
Remarks
Lifecycle: create with a root and a design size → AttachToParent(nint, bool) (window created) → SetPixelSize(int, int) / SetDpiScale(float) as the container dictates → Detach() (window destroyed) → Dispose(). A host can be attached again after a detach.
The container owns the message loop: no Application.Run inside a plug-in.
Constructors
UIHost(UIElement, Size, SizingMode)
Creates a host.
public UIHost(UIElement root, Size designSize, SizingMode sizing = SizingMode.Fixed)
Parameters
rootUIElementdesignSizeSizeLogical size of the editor at 100 %.
sizingSizingModeSizing behavior.
Properties
Animator
Animation engine.
public Animator Animator { get; }
Property Value
BackgroundColor
Background color cleared before drawing (defaults to the theme background).
public Color? BackgroundColor { get; set; }
Property Value
CapturedElement
Element holding the mouse capture.
public UIElement? CapturedElement { get; }
Property Value
DefaultLanguage
Language used by every host whose Language is null (default Auto:
the Windows display language of the user). Set it once at startup, e.g. from a plugin setting.
public static string DefaultLanguage { get; set; }
Property Value
DesignSize
Logical size of the design at 100 %.
public Size DesignSize { get; set; }
Property Value
DpiScale
System/host content scale (1 = 96 DPI).
public float DpiScale { get; }
Property Value
FocusedElement
Element with keyboard focus.
public UIElement? FocusedElement { get; }
Property Value
FollowWindowDpi
Follows DPI changes of the parent window (WM_DPICHANGED_AFTERPARENT). Plug-in adapters turn this off when the
DAW drives the scale explicitly (VST3 setContentScaleFactor).
public bool FollowWindowDpi { get; set; }
Property Value
FrameInterval
Interval of the frame timer (animations, meters). Default 16 ms (~60 fps).
public TimeSpan FrameInterval { get; set; }
Property Value
HasKeyboardFocus
true while the host window has the Win32 keyboard focus.
public bool HasKeyboardFocus { get; }
Property Value
HoveredElement
Deepest element under the mouse.
public UIElement? HoveredElement { get; }
Property Value
IsAttached
true while a native window exists.
public bool IsAttached { get; }
Property Value
IsDragging
true during an internal drag-and-drop operation.
public bool IsDragging { get; }
Property Value
IsLiveEditEnabled
Live layout editing (Ctrl+Shift+E): select elements, move and resize them with the mouse or the keyboard, then copy the resulting C# code (Ctrl+C) back into the editor source.
public bool IsLiveEditEnabled { get; set; }
Property Value
IsResizable
true if the container may let the user resize the editor.
public bool IsResizable { get; }
Property Value
KeepAspectRatio
Keeps the design aspect ratio when resizing in ScaleToFit.
public bool KeepAspectRatio { get; set; }
Property Value
Language
Language of the texts PluginUI displays in this host (dialog buttons, preset menu, tooltips…):
Auto, English, French or any code
registered with Register(string, UIStrings); null = DefaultLanguage.
Numbers always use a decimal point, whatever the language (see InvariantNumber).
public string? Language { get; set; }
Property Value
LiveEditShortcutEnabled
Enables the Ctrl+Shift+E live-edit shortcut.
public bool LiveEditShortcutEnabled { get; set; }
Property Value
LiveEditor
Live editor (created on first use).
public LiveEditor LiveEditor { get; }
Property Value
LogicalSize
Logical size the root is laid out in.
public Size LogicalSize { get; }
Property Value
MaxSize
Maximum logical size (resizable modes).
public Size MaxSize { get; set; }
Property Value
MidiLearn
MIDI learn back-end (null = no MIDI learn). When set, the right-click menu of controls bound to a parameter offers "MIDI Learn" / "Forget MIDI assignment", merged into the DAW's parameter menu by plug-in adapters.
public IMidiLearnService? MidiLearn { get; set; }
Property Value
MinSize
Minimum logical size (resizable modes).
public Size MinSize { get; set; }
Property Value
ModalBackdrop
Color drawn over the UI behind a modal popup.
public Color ModalBackdrop { get; set; }
Property Value
MousePosition
Last mouse position in DIPs.
public Point MousePosition { get; }
Property Value
ParameterContextMenuRequested
Called on right click over a control bound to a parameter (when the control has no own context menu):
lets the plug-in adapter show the DAW's parameter menu. Return true if handled.
public Func<IParameter, Point, bool>? ParameterContextMenuRequested { get; set; }
Property Value
- Func<IParameter, Point, bool>
PixelSize
Current size in physical pixels.
public (int Width, int Height) PixelSize { get; }
Property Value
Popups
Open popups, bottom to top.
public IReadOnlyList<Popup> Popups { get; }
Property Value
PreferredPixelSize
Pixel size the editor would like (design × DPI × zoom).
public (int Width, int Height) PreferredPixelSize { get; }
Property Value
ResizeRequestHandler
Asked by the host when it needs a new pixel size (zoom, DPI change, CornerResizer).
Return true if the container accepted (it then calls SetPixelSize(int, int)).
When null, the host resizes its own window.
public Func<int, int, bool>? ResizeRequestHandler { get; set; }
Property Value
Root
Root element.
public UIElement Root { get; set; }
Property Value
Scale
Pixels per DIP currently applied.
public float Scale { get; }
Property Value
Remarks
In ScaleToFit the design is scaled uniformly to fit both dimensions (a window with another aspect ratio leaves an empty band on the right or at the bottom).
ShowFocusRings
Draws keyboard focus rings (turned on by keyboard navigation, off by mouse clicks).
public bool ShowFocusRings { get; set; }
Property Value
Sizing
Sizing behavior.
public SizingMode Sizing { get; set; }
Property Value
Strings
Texts in effect: the table assigned here, or the table of Language. Assign a custom
UIStrings to override some texts for this host only; assign null to go back to the language table.
[AllowNull]
public UIStrings Strings { get; set; }
Property Value
TakeFocusOnClick
Gives the host window the keyboard focus on every click (standalone apps); plug-ins only take it for text input.
public bool TakeFocusOnClick { get; set; }
Property Value
TextMeasurer
Text measurement (device-accurate once a renderer exists).
public ITextMeasurer TextMeasurer { get; }
Property Value
Theme
Theme of every element in this host.
public Theme Theme { get; set; }
Property Value
ToolTipDelay
Delay before a tooltip appears.
public TimeSpan ToolTipDelay { get; set; }
Property Value
UnhandledException
Called when an exception is caught at a native boundary (window procedure, timers, posted actions). Exceptions never propagate into the host application; by default they are written to the debug output.
public static Action<Exception, string>? UnhandledException { get; set; }
Property Value
UseNativeMenus
Shows menus with the native Win32 menu instead of the custom-drawn popup.
public bool UseNativeMenus { get; set; }
Property Value
WindowHandle
Native window handle (0 when detached).
public nint WindowHandle { get; }
Property Value
Zoom
User zoom factor (Fixed and Relayout modes); changing it asks the container to resize.
public float Zoom { get; set; }
Property Value
Methods
AddTicker(ITickable)
Registers a per-frame callback (meters, scopes, custom animations). It runs on the UI thread until
Tick(double) returns false or RemoveTicker(ITickable) is called.
public void AddTicker(ITickable ticker)
Parameters
tickerITickable
AttachToParent(nint, bool)
Creates the child window inside parentHwnd at the current pixel size.
public void AttachToParent(nint parentHwnd, bool detectDpi = true)
Parameters
parentHwndnintParent window (DAW editor frame, standalone window...).
detectDpiboolReads the DPI of the parent and applies it (when the container does not provide a scale).
BeginDrag(UIElement, object, Action<bool>?)
Starts an internal drag-and-drop (call while the mouse button is held, e.g. from OnMouseMove(MouseEventArgs)). Elements under the pointer receive OnDragOver(DragEventArgs), the accepting one OnDrop(DragEventArgs).
public void BeginDrag(UIElement source, object data, Action<bool>? completed = null)
Parameters
sourceUIElementElement starting the drag.
dataobjectPayload.
completedAction<bool>Called with
trueif dropped on an accepting element.
BeginTextEdit(Rect, string, Action<string>, Action?, TextStyle?, Func<char, bool>?)
Shows a text box over bounds for in-place editing. Enter or a click outside commits,
Escape cancels.
public TextEditPopup BeginTextEdit(Rect bounds, string text, Action<string> commit, Action? cancel = null, TextStyle? style = null, Func<char, bool>? filter = null)
Parameters
boundsRectArea covered by the editor (DIP).
textstringInitial text (selected).
commitAction<string>Called with the final text when the user commits.
cancelActionCalled when the user cancels (Escape), or
null.styleTextStyleText style, or
nullfor the theme's default.filterFunc<char, bool>Character filter (return
falseto reject a typed character), ornull.
Returns
- TextEditPopup
The popup, already shown.
Exceptions
- ArgumentNullException
commitisnull.
BeginTextEdit(Rect, string, Func<string, bool>, Action?, TextStyle?, Func<char, bool>?)
Shows a text box over bounds for in-place editing with validation: when
tryCommit returns false the editor stays open, its frame turns red
(IsInvalid) and the text is selected for correction. Escape cancels; a click outside
commits a valid text and cancels an invalid one.
public TextEditPopup BeginTextEdit(Rect bounds, string text, Func<string, bool> tryCommit, Action? cancel = null, TextStyle? style = null, Func<char, bool>? filter = null)
Parameters
boundsRectArea covered by the editor (DIP).
textstringInitial text (selected).
tryCommitFunc<string, bool>Applies the text and returns
true, or returnsfalseto reject it.cancelActionCalled when the edit is cancelled, or
null.styleTextStyleText style, or
nullfor the theme's default.filterFunc<char, bool>Character filter (return
falseto reject a typed character), ornull.
Returns
- TextEditPopup
The popup, already shown.
Examples
host.BeginTextEdit(area, "0.5", text =>
{
if (!InvariantNumber.TryParse(text, out double v)) return false; // "0,5" is refused
myValue = v;
return true;
});
Exceptions
- ArgumentNullException
tryCommitisnull.
CaptureMouse(UIElement)
Gives the mouse capture to element.
public void CaptureMouse(UIElement element)
Parameters
elementUIElement
CheckAccess()
true on the UI thread (or before the window exists).
public bool CheckAccess()
Returns
CloseAllPopups()
Closes every popup.
public void CloseAllPopups()
ClosePopup(Popup)
Closes a popup and every popup opened after it (sub-menus).
public void ClosePopup(Popup popup)
Parameters
popupPopup
ConstrainPixelSize(ref int, ref int)
Clamps a proposed pixel size to the min/max size and aspect ratio.
public void ConstrainPixelSize(ref int pixelWidth, ref int pixelHeight)
Parameters
Detach()
Destroys the native window (the element tree is kept; the host can be attached again).
public void Detach()
DipToScreen(Point)
Converts a point in host DIPs to screen pixels (native menus, external windows).
public (int X, int Y) DipToScreen(Point point)
Parameters
pointPoint
Returns
DispatchKeyDown(KeyEventArgs)
Dispatches a key press. Returns true if handled (unhandled keys go back to the DAW).
public bool DispatchKeyDown(KeyEventArgs e)
Parameters
Returns
DispatchKeyUp(KeyEventArgs)
Dispatches a key release.
public bool DispatchKeyUp(KeyEventArgs e)
Parameters
Returns
DispatchMouseDown(Point, MouseButton, int, ModifierKeys)
Dispatches a mouse button press (DIPs).
public void DispatchMouseDown(Point p, MouseButton button, int clickCount, ModifierKeys modifiers)
Parameters
pPointbuttonMouseButtonclickCountintmodifiersModifierKeys
DispatchMouseMove(Point, ModifierKeys)
Dispatches a mouse move (DIPs). Public for custom containers and tests.
public void DispatchMouseMove(Point p, ModifierKeys modifiers)
Parameters
pPointmodifiersModifierKeys
DispatchMouseUp(Point, MouseButton, ModifierKeys)
Dispatches a mouse button release (DIPs).
public void DispatchMouseUp(Point p, MouseButton button, ModifierKeys modifiers)
Parameters
pPointbuttonMouseButtonmodifiersModifierKeys
DispatchTextInput(string)
Dispatches typed text to the focused element.
public bool DispatchTextInput(string text)
Parameters
textstring
Returns
DispatchWheel(Point, float, bool, ModifierKeys)
Dispatches a wheel event (DIPs, notches). Returns true if an element handled it.
public bool DispatchWheel(Point p, float notches, bool horizontal, ModifierKeys modifiers)
Parameters
pPointnotchesfloathorizontalboolmodifiersModifierKeys
Returns
DispatchWheel(float)
Wheel at the last known mouse position (VST3 onWheel).
public bool DispatchWheel(float notches)
Parameters
notchesfloat
Returns
Dispose()
Detaches (if needed) and releases every resource.
public void Dispose()
EnsureFrameTimer()
Starts the frame timer if it is not running (called by the animator and tickers).
public void EnsureFrameTimer()
EvictImage(object)
Releases the GPU copy of an image or SVG this host has drawn (it is rebuilt if drawn again). Device copies are cached per host until the window closes: evict images you replace dynamically (album art, waveforms...).
public void EvictImage(object imageOrSvg)
Parameters
imageOrSvgobject
Focus(UIElement?)
Moves the keyboard focus (null clears it). Returns false if the element cannot take it.
public bool Focus(UIElement? element)
Parameters
elementUIElement
Returns
GetParameterMenuItems(IParameter)
Menu entries PluginUI adds for a parameter (MIDI learn commands when MidiLearn is set), in the interface language. Plug-in adapters append them to the DAW's parameter menu.
public IReadOnlyList<MenuItem> GetParameterMenuItems(IParameter parameter)
Parameters
parameterIParameterThe parameter of the control that was right-clicked.
Returns
- IReadOnlyList<MenuItem>
The entries (possibly empty).
HideToolTip()
Hides the tooltip.
public void HideToolTip()
HideValueBubble(UIElement)
Hides the value bubble if owner shows it.
public void HideValueBubble(UIElement owner)
Parameters
ownerUIElement
HitAt(Point)
Deepest element under a point, popups included (null over a modal backdrop).
public UIElement? HitAt(Point point)
Parameters
pointPoint
Returns
Invalidate()
Requests a repaint (coalesced into one WM_PAINT).
public void Invalidate()
InvalidateLayout()
Requests a layout pass and a repaint.
public void InvalidateLayout()
MoveFocus(bool)
Moves the focus to the next (or previous) focusable element (Tab navigation).
public bool MoveFocus(bool forward)
Parameters
forwardbool
Returns
Post(Action)
Runs action on the UI thread (thread-safe). Actions posted while detached run after the next attach.
public void Post(Action action)
Parameters
actionAction
ProcessPostedActions()
Runs the posted actions now (UI thread; used by tests and offscreen hosts).
public void ProcessPostedActions()
ReleaseMouseCapture()
Releases the mouse capture (no OnCaptureLost() callback: voluntary release).
public void ReleaseMouseCapture()
RemoveTicker(ITickable)
Unregisters a per-frame callback.
public void RemoveTicker(ITickable ticker)
Parameters
tickerITickable
RenderToPng(string, float)
Renders the UI offscreen and saves it as PNG (documentation, previews, automated tests). Works whether or not the host is attached to a window.
public void RenderToPng(string path, float scale = 1)
Parameters
RequestKeyboardFocus()
Gives the Win32 keyboard focus to the host window (text input, standalone apps).
public void RequestKeyboardFocus()
RequestResize(int, int)
Requests a new pixel size from the container.
public bool RequestResize(int pixelWidth, int pixelHeight)
Parameters
Returns
SetDpiScale(float)
Sets the content scale (DPI / 96). The host asks the container for the matching pixel size through RequestResize(int, int) (in ScaleToFit the current size is scaled proportionally).
public void SetDpiScale(float scale)
Parameters
scalefloat
SetPixelSize(int, int)
Sets the pixel size (called by the container: VST3 onSize, window WM_SIZE...).
public void SetPixelSize(int pixelWidth, int pixelHeight)
Parameters
ShowMenu(IList<MenuItem>, Point)
Shows a menu at a point (context menus).
public void ShowMenu(IList<MenuItem> items, Point at)
Parameters
ShowMenu(IList<MenuItem>, Rect, PopupPlacement, float, Action?)
Shows a menu next to an anchor rectangle (drop-downs, menu buttons).
public void ShowMenu(IList<MenuItem> items, Rect anchor, PopupPlacement placement = PopupPlacement.Below, float minWidth = 0, Action? closed = null)
Parameters
itemsIList<MenuItem>Entries.
anchorRectAnchor in host DIPs.
placementPopupPlacementPlacement relative to the anchor.
minWidthfloatMinimum width (e.g. the drop-down width).
closedActionCalled when the menu closes (chosen or dismissed).
ShowPopup(Popup)
Shows a popup above the UI (it is laid out at the next frame).
public void ShowPopup(Popup popup)
Parameters
popupPopup
ShowToolTip(string, Rect, UIElement?)
Shows a tooltip immediately at an anchor (custom tooltips; normal tooltips use ToolTip).
public void ShowToolTip(string text, Rect anchor, UIElement? owner = null)
Parameters
ShowValueBubble(UIElement, string)
Shows (or updates) the value bubble above owner.
public void ShowValueBubble(UIElement owner, string text)
Parameters
StepFrame(double)
Advances animations and tickers by dt seconds (driven by the frame timer; public for tests and snapshots).
public void StepFrame(double dt)
Parameters
dtdouble
UpdateLayout()
Runs the layout pass now if needed.
public void UpdateLayout()
Events
Attached
Raised after the native window was created.
public event Action<UIHost>? Attached
Event Type
Detaching
Raised before the native window is destroyed.
public event Action<UIHost>? Detaching
Event Type
FilesDropped
Raised when files are dropped where no element accepted them.
public event Action<UIHost, FilesDroppedEventArgs>? FilesDropped
Event Type
FocusChanged
Raised when the keyboard focus moves.
public event Action<UIHost, UIElement?>? FocusChanged
Event Type
FrameTick
Raised on every frame-timer tick while animations or tickers are active.
public event Action<UIHost, double>? FrameTick
Event Type
KeyboardFocusChanged
Raised when the host window gains or loses the Win32 keyboard focus.
public event Action<UIHost, bool>? KeyboardFocusChanged
Event Type
LiveEditChanged
Raised when live edit mode is turned on or off.
public event Action<UIHost, bool>? LiveEditChanged
Event Type
PreviewKeyDown
Raised before a key is dispatched to the focused element (global shortcuts). Set Handled to stop it.
public event Action<UIHost, KeyEventArgs>? PreviewKeyDown