WPF & PowerShell – Part 7 (Sharing Hosts)

Well here we are at the end of a week of WPF.  We’ve learned how to create basic, simple user interactive interfaces.  We’ve seen a brief glimmer of the golden UI layer that is WPF, and have seen how we can use PowerShell to add easy interactivity to XAML.  You’ve seen tricks to help you work your way through .NET code, and help you unwrap the mysteries of WPF. We’ve seen how we can use PowerShell’s list processing technology allows for simple binding to WPF’s controls, and how WPF applets can help you present a simple front ends to PowerShell functionality.  We’ve gotten a very brief taste of what the pipeline can bring to User interfaces, and we’ve showed you how to make controls that run in the background so you can build your control in PowerShell and still use PowerShell.

The last trick to learn is how to maintain the streaming behavior with PowerShell.  There are two cases that are useful: streaming data into a command so that you can update information in a control, and streaming information from a control.  While some commands have taken input and output, they have not updated their contents as items come in from the pipeline, nor have they outputted items onto the pipeline while still showing as a dialog.  The trick to doing both of these things was there in yesterday’s post.  The update to Show-Control happens to include a line that makes sure the background runspace has a variable pointing to the foreground runspace.  Using this, and a new CTP2 feature, PowerShell events, you can stream data from one runspace to the other so you can update a control as data comes in.  You can also generate events in the host runspace, which gives you a way to stream data back from the original command.  Having the host runspace also lets you run code in that runspace, and, since you have your original host, you can also write output, error messages, progress bars, and more in the original runspace from the background runspace.

Since you can share simple data between runspaces in this way, you could also use PowerShell to create mutli-document interfaces with WPF.  With PowerShell remoting in the picture, you can easily make front ends or status monitors for remote tasks, or use a hefty remote backend to make working on lightweight clients easier (remember, both PowerShell v2 and WPF run on all operating systems after XP).

For the final sample we’ll go back to our Select Command example, and we’ll give it an option to output the help in the current runspace, or get the command syntax.  As you can see below, the code that produces this is still pretty short.  With a few new buttons come a few new click handlers, but writing to the host output is quick, simple, and easy (remember, $parentHost is a variable set by Show-Control in a background runspace it creates).  All of the code that interacts with the original host is in the last 3 event handlers.

<StackPanel xmlns=’http://schemas.microsoft.com/winfx/2006/xaml/presentation’>
<Label FontSize=’14’>Type a Command</Label>
<TextBox Name=”CommandTextBox”/>
<ListBox Name=”CommandListBox” Width=’200′ Height=’200’/>
<Button Name=”ShowHelp” FontSize=’14’>Show Help</Button>
<Button Name=”ShowSamples” FontSize=’14’>Show Samples</Button>
<Button Name=”OutputCommand” FontSize=’14’>Output</Button>
“@ | Show-Control @{
   “CommandTextBox.TextChanged” = {      
       $listBox = $window.Content.FindName(“CommandListBox”)
       $textBox = $window.Content.FindName(“CommandTextBox”)
       $listBox.ItemsSource = @(Get-Command “*$($textbox.Text)*” | % { $_.Name })
   “CommandListBox.SelectionChanged” = {
       $textBox = $window.Content.FindName(“CommandTextBox”)
       $textBox.Text = $this.SelectedItem
   “ShowHelp.Click” = {
       $textBox = $window.Content.FindName(“CommandTextBox”)
       $helpText = (Get-Help $textBox.Text -detailed -ea SilentlyContinue) | Out-String      
   “ShowSamples.Click” = {
       $textBox = $window.Content.FindName(“CommandTextBox”)
       $helpText = (Get-Help $textBox.Text -example -ea SilentlyContinue) | Out-String      
   “OutputCommand.Click” = {$parentHost.UI.Write($textBox.Text)}
} -backgroundRunspace

This series should have armed you with the technical skill set required in order to create user interfaces in script.  The series has been largely rebuilt from my notes and scripts built when first exploring the interaction of WPF and PowerShell after STA mode was enabled.  These are designed primarily to be technical examples and a quickstart in the topic.  Hopefully this series has gotten you up to speed with some of the possibilities of using PowerShell and WPF together, but please stay tuned.  While this week has been about giving you the basics, starting next week (and every week) I’ll post a new, useful small UI built with WPF and PowerShell.

I hope you enjoyed the series and I hope you get inspired to write a few quick UIs as scripts yourself.

Hope this Helps,
James Brundage [MSFT]