Build Your First GUI Plugin
Build Your First GUI Plugin
Note: We'll use Visual Studio 2022 (or 2019) for this purpose
1) In Visual Studio, Create a Class Library project

2. Choose .NET Framework 4.6.1

3. Remove "Class1" and add a new UserControl

4. From the Toolbox, add a "Label" object

5. Add reference to Stream.Common.Shared.

6. Here's a simple code in both C# and VB.NET
C# Example:
using Stream.Common.Shared;
using System;
using System.Windows.Forms;
namespace SimpleLabelPlugin
{
// Note: Inherits UserControl for designer support, implements IPluginView directly
// Cannot inherit from PluginViewBase due to single inheritance limitation
public partial class SimpleLabelPlugin : UserControl, IPluginView
{
private IHostServices _host;
public string Tag1 { get; set; }
public string Tag2 { get; set; }
public SimpleLabelPlugin()
{
InitializeComponent(); // <-- create label1 and wire designer events
this.Load += SimpleLabelPlugin_Load; // optional
this.Click += SimpleLabelPlugin_Click; // optional
}
private void SimpleLabelPlugin_Load(object sender, EventArgs e)
{
}
public void Initialize(IHostServices host)
{
_host = host;
}
public Control GetControl()
{
return this;
}
private void SimpleLabelPlugin_Click(object sender, EventArgs e)
{
MessageBox.Show("Clicked");
//Examples:
//_host.Tags.WriteValue(Tag2, any_value);
}
public void PluginUpdate()
{
try
{
if (_host?.Tags != null && !string.IsNullOrEmpty(Tag1))
{
this.label1.Text = _host.Tags.ReadValue(Tag1)?.ToString() ?? "N/A";
}
}
catch
{
// Code to run in case of Exception
}
}
}
}
VB.NET Example:
Imports System.Windows.Forms
Imports Stream.Common.Shared
' Note: Inherits UserControl for designer support, implements IPluginView directly
' Cannot inherit from PluginViewBase due to single inheritance limitation
Public Class SimpleLabelPluginVB
Inherits UserControl
Implements IPluginView
Private _host As IHostServices
Public Property Tag1 As String
Public Property Tag2 As String
Public Sub Initialize(host As IHostServices) Implements IPluginView.Initialize
_host = host
End Sub
Public Function GetControl() As Control Implements IPluginView.GetControl
Return Me
End Function
Private Sub SimpleLabelPluginVB_Click(sender As Object, e As EventArgs) Handles Me.Click
'_host.Tags.Write("Pump1.Speed_SP", Now.Second)
MsgBox("clicked")
'Examples:
'_host.Tags.WriteValue(Tag2, any_value)
End Sub
Public Sub PluginUpdate()
Try
If _host Is Nothing OrElse _host.Tags Is Nothing Then Return
' Read multiple tags at once using ReadValues
Dim tagNames = {Tag1, Tag2}
Dim values = _host.Tags.ReadValues(tagNames)
' Update Label1 with Tag1 value
If Not String.IsNullOrEmpty(Tag1) AndAlso values.ContainsKey(Tag1) Then
Dim value1 = values(Tag1)
Me.Label1.Text = If(value1?.ToString(), "N/A")
Else
Me.Label1.Text = "N/A"
End If
' Update Label2 with Tag2 value
If Not String.IsNullOrEmpty(Tag2) AndAlso values.ContainsKey(Tag2) Then
Dim value2 = values(Tag2)
Me.Label2.Text = If(value2?.ToString(), "N/A")
Else
Me.Label2.Text = "N/A"
End If
Catch ex As Exception
' Silently handle errors to prevent plugin from crashing the host
Me.Label1.Text = "Error"
Me.Label2.Text = "Error"
Debug.WriteLine($"[SimpleLabelPluginVB] Error in PluginUpdate: {ex.Message}")
End Try
End Sub
Private Async Sub btnOpenWindow_Click(sender As Object, e As EventArgs) Handles btnOpenWindow.Click
Await OpenWindow()
End Sub
Async Function OpenWindow() As Task
Try
' Check if navigation service is available
If _host Is Nothing OrElse _host.Navigation Is Nothing Then
MsgBox("Navigation service not available", MsgBoxStyle.Exclamation)
Return
End If
' Build dynamic properties dictionary
' Keys are placeholders (e.g., {CONTROLLER_NAME}) that will be substituted in the target window
' Values are the actual values to use
Dim dynamicProps As New Dictionary(Of String, String) From {
{"{CONTROLLER_NAME}", "C002"},
{"{CONTROLLER_ALARM}", "ControllerAlarms"},
{"{CONTROLLER_LABEL}", "C002_Label"}
}
' Serialize to JSON for the navigation service
Dim jsonDict As String = JsonConvert.SerializeObject(dynamicProps)
' Open as popup with dynamic properties
Dim options As New WindowOpenOptions With {
.WindowName = "Details.edd",
.WindowTitle = "Controller Details",
.IsPopup = True,
.IsTopMost = True,
.KeepCurrentWindow = True,
.DynamicPropertiesJson = jsonDict
}
Dim success = Await _host.Navigation.OpenWindowWithOptions(options)
If Not success Then
MsgBox("Failed to open window. Check if the page exists.", MsgBoxStyle.Exclamation)
End If
Catch ex As Exception
MsgBox($"Error opening window: {ex.Message}", MsgBoxStyle.Critical)
End Try
End Function
End Class
7. Build the project, and locate the dll file

8. Copy the dll file (and all preerquistes) to Stream application folder under "Plugins\plugin name"

9. In the Graphics Builder, place a new "GUI Plugin" and select the required one.


10. Notice the properties (matching the global properties in the dll)

11. You can use Tags or Dynamic Parameters (or any static values as it doesn't have to be Tags).