Automating the world one-liner at a time…
In the last post we met XAML, and I gave you a core function (Show-Control) that will help you make interactive WPF controls quite nicely in PowerShell.
You can see that, by using Show-Control, it is possible to reduce the size and complexity of a script that creates UI. Today, I'll show you how to build small applications by building functions and modules you can use later.
But before we get into that, I'll explain some more of the benefits I see of using scripts to produce user interfaces:
Let's focus on the 3rd benefit as we build up a few controls that rely on each other. First, let's make a Controls module and put an updated Show-Control in it. The only difference between this Show-Control and the other Show-Control is that it emits an item. Whatever is stored in the Tag property of Window is emitted whenever our control is closed. This means that you can catch when the window closes and pack information into the tag so it can be emitted into the pipeline. This is important to remember, because we'll use it to create some commands from Get-Listbox.
To create a package, create a directory called Packages under Documents\WindowsPowerShell. In this directory, create a folder called Controls. Create a file, Controls.psm1 in this directory.
A PSM1 file is a module file. It declares a number of functions that you can import as a group by using Add-Module. In a PSM1 file, a variable, $psScriptRoot exits. This is the path where the module is installed. Personally, I like to write my modules so that they just dot source other files in the same directory that contain the functions in the module. This way, each function is easy to locate because it is in it's own file, but you can still import them all as a group. Remember, however, that since PowerShell is an interpreted language, you'll need to import the functions in order. Right now, it doesn't matter, because Get-Listbox doesn't have anything to do with Show-Control yet.
In this module, I'll start with the following lines
. $psScriptRoot\Get-Listbox.ps1
. $psScriptRoot\Show-Control.ps1
Since this series is starting to have a little too much inline code, this time I'm attaching the scripts. Get-Listbox will return you a listbox from an enumerated type, an existing type, or a list of strings. Load them into your runspace by typing "Add-Module Control". When you're done, you might want to add the functions below to the module.
I can easily turn Get-Listbox into Select-Listbox, which will display the control and emit the item the user picked onto the pipeline.
See:
function Select-Listbox() { if ($input) { $listBox = $input | Get-Listbox } else { $listBox = $args | Get-Listbox } $listBox | Show-Control @{ "Window.Closed" = {$window.Tag = $window.Content.SelectedItem} "MouseDoubleClick" = {$window.Close()} } }
And I can also put Get-Listbox together with Get-History to give me Get-HistoryListbox, and Select-Listbox together with Get-History to give me Select-History, and Select-History can be used to create Invoke-History
function Get-HistoryListbox() { Get-History | % { $_.CommandLine } | Get-Listbox }
function Select-History() { Get-History | % { $_.CommandLine } | Select-Listbox }
function Invoke-History() { Select-History | Invoke-Expression }
A much more advanced example of using WPF to create a function to select output is called Select-Grid and has been written by Jaykul Bennett You can find more information about it HERE.
Let's make a couple more quick controls, Get-VideoPlayer and use the same technique to build Show-Video to give you a teaser for tomorrow.
function Get-VideoPlayer($file) { $mediaPlayer = New-Object Windows.Controls.MediaElement $mediaPlayer.Source = New-Object System.URI (Resolve-Path $file) $mediaPlayer.LoadedBehavior = "Manual" $mediaPlayer }
Now lets build a basic Show-Video:
function Show-Video($file) { $videoPlayer = Get-VideoPlayer $file $videoPlayer.AllowDrop =$true $videoPlayer | Show-Control @{ "Drop"={ $this.Source = New-Object System.URI ($_.Data.GetFileDropList() | select -first 1) $this.Play() } "Window.Activated" = {$window.Content.Play() } "Window.Closed"={$window.Content.Stop()} } }
Tomorrow, we'll take Show-Video and Get-VideoPlayer and turn them into a video player with some controls, and we'll show you how to run controls in the background.
Hope this Helps, James Brundage [MSFT]
PingBack from http://www.alvinashcraft.com/2008/05/26/dew-drop-may-26-2008/
OK, so I've created XAML forms from Powershell, and have the event handling technique figured out. But recently, I've started playing with PowershellASP. What I'd really love to be able to do is create a web page using XAML (not just a windows application), and implement the code-behind for the events in Powershell, instead of C#.
I haven't found any solution for this...but I have a feeling that if it were possible, it would blow open a lot more doors for Powershell...