Windows

io.Connect Windows

In order for windows created from external WPF or WinForms apps to become io.Connect Windows, they must first be registered via the .NET Window Management API.

Registering your .NET apps as io.Connect Windows must happen at the correct moment - when the process of creating and rendering your window has completed and you have a reference to its handle. For WPF apps, you should register the window in the Loaded event, for WinForms apps - using the OnShown() method. If you are using custom UI frameworks, you should make sure to choose an event where you are certain that all your components have been properly rendered and you have the window handle. If you try to register an io.Connect Window too early, the registration may fail or may interfere with the process of creating and rendering the components of your .NET app.

⚠️ Note that you should make sure you are running io.Connect Desktop and your interop-enabled .NET apps with matching user privileges (e.g., when debugging). Otherwise, window registration will fail - your app window won't be sticky and another transparent sticky window will be visible, looking as if the borders of your app window have been separated from the window itself. If you are running your app as an Elevated administrator (e.g., from Visual Studio, or any IDE, which runs in an elevated state), then you must also run io.Connect Desktop in an elevated state, if possible. Another solution for matching the user privilege states of io.Connect Desktop and your app when debugging is to put Debugger.Launch() in the app code and start the app by launching its EXE file from the Windows Explorer. This will cause the app to run with standard user privileges.

Window Options

You can set several window configuration options during window registration. To create an instance with window options, use:

var ioConnectWindowOptions = new GlueWindowOptions();

If the app is started by io.Connect Desktop, you can get any window startup options (regarding the app bounds, Layout, etc.) by using:

var ioConnectWindowOptions = io.GlueWindows.GetStartupOptions() ?? new GlueWindowOptions();

Window Type

To set the type of the window:

// Create a flat window.
ioConnectWindowOptions.WithType(GlueWindowType.Flat);

// Create a tab window.
ioConnectWindowOptions.WithType(GlueWindowType.Tab);

Window Title

To set the title of the window:

ioConnectWindowOptions.WithTitle("My Window");

Registering Windows

To register a window as an io.Connect Window, use the RegisterWindow() method passing the window object as a first parameter and a window options object as a second:

IGlueWindow ioConnectWindow = await io.GlueWindows.RegisterWindow(this, ioConnectWindowOptions);

WPF Windows

⚠️ Note that it is mandatory for an external WPF app to have an app.manifest file with the following section:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
        <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
    </windowsSettings>
</application>

You can register a WPF window right after its creation. You can do this either in the window code or from an external component. To register a WPF window, use:

// Register the window by using `this` window as a first parameter.
IGlueWindow ioConnectWindow = await io.GlueWindows.RegisterWindow(this, ioConnectWindowOptions);

Full example:

// Get and set window options.
var ioConnectWindowOptions = io.GlueWindows.GetStartupOptions() ?? new GlueWindowOptions();

ioConnectWindowOptions.WithType(GlueWindowType.Tab);

ioConnectWindowOptions.WithTitle("My Window");

// Register the window.
IGlueWindow ioConnectWindow = await io.GlueWindows.RegisterWindow(this, ioConnectWindowOptions);

WPF windows are automatically unregistered when they are closed. If you want to manually unregister a window at a different point in time, use:

ioConnectWindow.Unregister();

See the .NET WPF window registration example on GitHub.

WinForms Windows

You can register a WinForms window by using its handle:

// Get and set window options.
var ioConnectWindowOptions = io.GlueWindows.GetStartupOptions() ?? new GlueWindowOptions();

ioConnectWindowOptions.WithType(GlueWindowType.Flat);

ioConnectWindowOptions.WithTitle("My Window");

// Register the window by using its handle as a first parameter.
IGlueWindow ioConnectWindow = await io.GlueWindows.RegisterWindow(this.Handle, ioConnectWindowOptions);

WinForms windows don't support automatic unregistration. You should explicitly call Unregister() when the window is closed:

ioConnectWindow.Unregister();

Registering Windows as App Instances

The .NET Window Management library allows WPF and WinForms apps to announce the windows initiated by them as io.Connect app instances (see also App Management). This is necessary when you have a multi window app and its windows are registered as io.Connect apps - then the multi window app becomes responsible for notifying io.Connect Desktop about new app instances.

The RegisterAppWindow() method registers the window both as an io.Connect Window and as an io.Connect app instance. It accepts the WPF window object (or the WinForms window handle), the io.Connect app object, the app name and an app options builder as arguments:

var placement = new GlueWindowScreenPlacement();

io.GlueWindows.RegisterAppWindow(myWindow, myApp, myWindowAppName,
        // Specify app options.
        builder => builder
        .WithPlacement(placement)
        .WithType(GlueWindowType.Tab));

For more details on multi window app support, see App Management > Multi Window Apps and the .NET Multi Window Demo example on GitHub.

Window Operations

Once an app window is registered, the Window Management API will accept full control over the window positioning, sizing and visibility. The app shouldn't use native methods (e.g., WPF or WinForms calls) to control the window as this will interfere with the io.Connect Window Management.

You can perform operations on the current window and on any other registered window.

Window App Instance

The window object offers access to the host app instance, connecting the Window Management API with the App Management API:

IAppManagerApplication appInstance = targetWindow.Instance;

Current Window

To get a reference to the current window, use:

IGDWindow myWindow = await io.GlueWindows.RegisterWindow(this, ioConnectWindowOptions);

Title

To set the window title, use:

myWindow.Title = "New title";

Size & Position

To change the bounds of the window, use:

// Set the window bounds - left, top, width, height.
var newWindowBounds = new GlueWindowBounds(10, 10, 200, 200);

myWindow.Bounds = newWindowBounds;

Visibility

To hide the window, use:

myWindow.IsVisible = false;

Handling Other Windows

The .NET Window Management API allows you to find all io.Connect Windows and manipulate them.

Finding Windows

To find all io.Connect Windows, use the GetGDWindows() method of the .NET Window Management API:

IGDWindow[] allWindows = await io.GlueWindows.GetGDWindows();

To await your newly registered window to be published to the window collection, use:

IGDWindow myWindow = await io.GlueWindows.RegisterWindow(this, ioConnectWindowOptions);

await io.GlueWindows.AwaitWindow(window => window.Id == myWindow.Id);

// The collection will now contain `myWindow`.
IGDWindow[] allWindows = await io.GlueWindows.GetGDWindows();

To find a window by ID, use:

var targetWindowId = "29476_0";
IGDWindow[] allWindows = await io.GlueWindows.GetGDWindows();
IGDWindow targetWindow = allWindows.FirstOrDefault(window => window.Descriptor.Id == targetWindowId);

To find a window by name, use:

var targetWindowName = "target-window";
IGDWindow[] allWindows = await io.GlueWindows.GetGDWindows();
IGDWindow targetWindow = windows.FirstOrDefault(window => window.Descriptor.Name == targetWindowName);

To find the main window of an app instance by app instance ID, use:

var instanceId = "29476_1";
IGDWindow mainWindow = await io.GlueWindows.AwaitWindow(window => window.Id == instanceId);

To find all windows of any app, use:

var appName = "client-list";
IEnumerable<IGDWindow> appWindows = (await io.GlueWindows.GetGdWindows())
    .Where(window => window.Descriptor.Name == appName);

To find all windows of the current app, use:

var appWindows = io.GlueWindows.OwnWindows;

Updating Windows

To manipulate any io.Connect Window, use the Update() method of the window instance.

Window Title

IGDWindow[] allWindows = await io.GlueWindows.GetGDWindows();
var newTitle = "New Title";
IGDWindow targetWindow = allWindows.FirstOrDefault((window) =>
{
    return window.Descriptor.Name == "My Window";
});

await targetWindow.Update((window) =>
{
    window.SetTitle((titleOptions) => titleOptions.Title = newTitle);
});

Hiding Windows

await targetWindow.Update((window) =>
{
    window.Hide();
});

Showing Windows

await targetWindow.Update((window) =>
{
    window.Show();
});

Closing Windows

await targetWindow.Update((window) =>
{
    window.Close();
});

Window Events

The .NET Window Management API offers methods for listening for io.Connect Window events. To get notified for window events, use the Subscribe() method directly on an API level or on a window instance.

The example below demonstrates subscribing for an event by using Subscribe() on an API level:

var subscription = io.GlueWindows.Subscribe(
    // Reference to the window for which to receive event notifications.
    targetWindow,
    // The lambda specifies for which window property to receive event notifications.
    p => p.Title,
    // Event handler.
    (descriptor, eventType, propertyChangedName, newPropertyValue, oldValue) =>
        {
            var title = descriptor.Title;
        }
);

To stop listening for any window event, use the Dispose() method of the subscription object returned by Subscribe():

subscription.Dispose();

Some of the available window events are described below. The examples demonstrate how to subscribe for them through the window instance.

Title

To get notified when the window title changes:

var subscription = window.Subscribe(
    EventType.TitleChanged,
    (descriptor, eventType) =>
        {
            var title = descriptor.Title;
        }
);

Bounds

To get notified when the window bounds change:

var subscription = window.Subscribe(
    EventType.BoundsChanged,
    (descriptor, eventType) =>
        {
            var bounds = descriptor.Bounds;
        }
);

Visibility

To get notified when the window visibility changes:

var subscription = window.Subscribe(
    EventType.VisibilityChanged,
    (descriptor, eventType) =>
        {
            var isVisible = descriptor.isVisible;
        }
);

Frame Color

To get notified when the window frame color changes:

var subscription = window.Subscribe(
    EventType.FrameColorChanged,
    (descriptor, eventType) =>
        {
            var frameColor = descriptor.FrameColor;
        }
);

Frame Buttons

The Window Management API allows placing custom buttons in the frame area of the window and handling clicks on them.

To add a frame button, use the Update() method of an io.Connect Window instance. The following example demonstrates how to add a frame button, specify an icon for it and handle clicks on it:

ioConnectWindow.Update(windowUpdate => windowUpdate.AddButton(button =>
    {
        button.ButtonId = "btn" + Guid.NewGuid().ToString("N");
        // To set a button icon, you can also use `button.ImageBase64` and supply the respective Base64-encoded string.
        button.Image = Image.FromFile("button-image.png");
        button.OnClickAction = (@event, buttonInfo) =>
        {
            // Handle button clicks.
        };
    }));

WPF Example

This is a minimalistic WPF example that registers its main window as an io.Connect Window.

See the .NET WPF example on GitHub.

In App.xaml initialize io.Connect:

public partial class App : Application
{
    public static Glue42 IOConnect;

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        IOConnect = new Glue42();
        IOConnect.Initialize("MyDemo");
    }

In MainWindow.xaml.cs register the window:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var ioConnectWindowOptions = App.IOConnect.GlueWindows.GetStartupOptions() ?? new GlueWindowOptions();
        ioConnectWindowOptions.WithType(GlueWindowType.Flat);
        ioConnectWindowOptions.WithTitle("Example Window");

        // Register the window.
        App.IOConnect.GlueWindows.RegisterWindow(this, ioConnectWindowOptions)
            .ContinueWith(r =>
            {
                IGlueWindow ioConnectWindow = r.Result;
            });
    }
}