WinUIShell

repository·main·Indexed 43 days ago

https://github.com/mdgrs-mei/winuishell

A PowerShell module for creating WinUI 3 applications using an IPC-based server model. It allows PowerShell scripts to drive high-performance Windows UI elements without loading WinUI 3 DLLs directly into the PowerShell process, supporting non-blocking UI, thread-safe property access, and XAML-based UI construction. Requires PowerShell 7.4+ and Windows 10/11 build 10.0.17763.0 or newer.

Tokens
2.5K
Snippets
7
Records
16
Agent score
5%

What's inside WinUIShell

  1. How WinUIShell works

    main

    WinUIShell operates by launching a server process, WinUIShell.Server.exe, which provides all UI functionalities. The PowerShell module communicates with this server via IPC (Inter-Process Communication).

    Key Benefits:

    • No WinUI 3 DLLs in PowerShell: The module avoids loading heavy WinUI 3 DLLs directly into the PowerShell process.
    • Non-blocking UI: You can run long-running code in event handlers without blocking the GUI.
    • Thread-safe Property Access: You can access and modify UI element properties directly from any thread without needing to use Dispatchers.
  2. Manage multiple runspaces and independent event callbacks

    main
    WinUIShell allows event callbacks to be handled independently across multiple user-defined runspaces. This is demonstrated in MultipleRunspaces.ps1, which shows how to maintain responsiveness and handle events in a multi-runspace environment.
  3. Configure Event Callback Runspace Modes

    main

    The RunspaceMode property of an EventCallback determines how and where the script block executes:

    • MainRunspaceAsyncUI (Default): Runs in the main runspace where the module is loaded. It is asynchronous (AsyncUI), meaning it does not block the UI thread on the server. If a callback is long-running, subsequent events are queued. Use DisabledControlsWhileProcessing to prevent UI confusion during queuing.
    • MainRunspaceSyncUI: Runs in the main runspace but blocks the UI thread on the server until completion. This is useful for events that require synchronous execution, such as BeforeTextChanging on a TextBox.
    • RunspacePoolAsyncUI: Handles callbacks in parallel using multiple runspaces in a pool. This is ideal for multiple long-running tasks that must remain responsive. Use Set-WUIRunspacePoolOption to configure the pool size and initialization scripts.
    # Configure a Runspace Pool
    Set-WUIRunspacePoolOption -RunspaceCount 5 -InitializationScript {
        param ($ScriptRoot)
        $globalVar = 'Global variable in the runspace.'
        function GlobalFunction() {
            'Global function in the runspace.'
        }
    } -InitializationScriptArgumentList $PSScriptRoot
  4. WinUIShell Requirements

    main

    To use WinUIShell, ensure your environment meets the following requirements:

    • PowerShell: version 7.4 or newer
    • Windows: version 10/11 build 10.0.17763.0 or newer
  5. Handle long-running tasks with RunspacePoolAsyncUI

    main

    For tasks that take a significant amount of time, use RunspacePoolAsyncUI. This allows you to manage long-running operations without blocking the main UI thread. Examples include:

    • Single Task: Using CancelLongRunningEventCallback.ps1 to show how to manage a single long-running task.
    • Multiple Tasks: Using MultipleProgressBars.ps1 to manage multiple concurrent long-running tasks with progress indicators.
    • Dialogs: Using InstallDialog.ps1 to show a dialog at the top of the screen for a single long-running task.
  6. Create UI using XamlReader

    main

    You can define your UI using XAML strings instead of imperative code. Use [XamlReader]::Load($xamlString) to instantiate the UI. To interact with specific elements defined in XAML, use the FindName method on a FrameworkElement (note: Window does not have FindName, so you must call it on the Content of the window).

    Limitations: You cannot use x:Class attributes or code-behind bindings in your XAML.

    using namespace WinUIShell.Microsoft.UI.Xaml.Markup
    
    $xamlString = @'
    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
            <Button x:Name="button" Content="Click Me"/>
        </StackPanel>
    </Window>
    '@
    
    $win = [XamlReader]::Load($xamlString)
    $win.AppWindow.ResizeClient(400, 200)
    
    # Access the button via FindName on the Content
    $button = $win.Content.FindName('button')
    $button.AddClick({
        $button.Content = 'Clicked!'
    })
    
    $win.Activate()
    $win.WaitForClosed()
  7. Quick Start: Create a Window with a Button

    main

    This example demonstrates how to initialize a WinUI 3 window, create a button, and handle a click event using WinUIShell namespaces.

    using namespace WinUIShell.Microsoft.UI.Xaml
    using namespace WinUIShell.Microsoft.UI.Xaml.Controls
    Import-Module WinUIShell
    
    $win = [Window]::new()
    $win.Title = 'Hello from PowerShell!'
    $win.AppWindow.ResizeClient(400, 200)
    
    $button = [Button]::new()
    $button.Content = 'Click Me'
    $button.HorizontalAlignment = 'Center'
    $button.VerticalAlignment = 'Center'
    $button.AddClick({
        $button.Content = 'Clicked!'
    })
    
    $win.Content = $button
    # Activate() shows the window but does not block the script.
    $win.Activate()
    $win.WaitForClosed()