{"id":6081,"date":"2008-05-26T05:48:00","date_gmt":"2008-05-26T05:48:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/powershell\/2008\/05\/26\/wpf-powershell-part-5-using-wpf-powershell-modules\/"},"modified":"2019-02-18T13:15:53","modified_gmt":"2019-02-18T20:15:53","slug":"wpf-powershell-part-5-using-wpf-powershell-modules","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/wpf-powershell-part-5-using-wpf-powershell-modules\/","title":{"rendered":"WPF &#038; PowerShell &#8211; Part 5 ( Using WPF &#038; PowerShell Modules)"},"content":{"rendered":"<p>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.<\/p>\n<p>You can see that, by using Show-Control, it is possible to reduce the size and complexity of a script that creates UI.&nbsp; Today, I&#8217;ll show you how to build small applications by building functions and modules you can use later.<\/p>\n<p>But before we get into that, I&#8217;ll explain some more of the benefits I see of using scripts to produce user interfaces:<\/p>\n<ul>\n<li>Flexible Dependencies<\/li>\n<ul>\n<li>If I compile an application, I have forced my customers to forever use the custom controls I have built in an application.&nbsp; Using script, I can reuse controls that match a signature a run time, instead of being locked into the same choice forever.&nbsp; I also am encouraged to make each part of my application something that can be flexibly depended on.&nbsp; This encourages an ecosystem of compact, reusable controls written as scripts.<\/li>\n<\/ul>\n<li>Size \/ Memory Consumption<\/li>\n<ul>\n<li>Because each script is not running in its own application space, the additional overhead of an executable per window goes away.&nbsp; Also, the scripts themselves are smaller and easier to distribute.<\/li>\n<\/ul>\n<li>Discoverability &amp; the Visual Pipeline<\/li>\n<ul>\n<li>All applications, in my opinion, can be thought of as a pipeline.&nbsp; Much as PowerShell pipelines may end up nested, so may pipelines of interfaces, but I believe it is possible to think of applications in this way.&nbsp; I also believe that when you think of an application this way, describing the application in Verb-Noun pairs makes is a natural way of thinking about it.&nbsp; Think, for instance, of the application a customer service representative has to go through to look at your account.&nbsp; It be thought of like this: \n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Get-UserFullName | Search-User | Get-UserConfirmationInformation | Get-UserIdentifyingInformation | Show-UserRecord <\/p>\n<p>When you think about user interfaces in this way, the benefit of expressing small controls as Verb-Noun pairs becomes clear, as does the usefulness of using Get-Command to help discover what controls exist.<\/li>\n<\/ul>\n<\/ul>\n<p>Let&#8217;s focus on the 3rd benefit as we build up a few controls that rely on each other.&nbsp; First, let&#8217;s make a Controls module and put an updated Show-Control in it.&nbsp; The only difference between this Show-Control and the other Show-Control is that it emits an item.&nbsp; Whatever is stored in the Tag property of Window is emitted whenever our control is closed.&nbsp; This means that you can catch when the window closes and pack information into the tag so it can be emitted into the pipeline.&nbsp; This is important to remember, because we&#8217;ll use it to create some commands from Get-Listbox.<\/p>\n<p>To create a package, create a directory called Packages under Documents\\WindowsPowerShell.&nbsp; In this directory, create a folder called Controls.&nbsp; Create a file, Controls.psm1 in this directory.<\/p>\n<p>A PSM1 file is a module file.&nbsp; It declares a number of functions that you can import as a group by using Add-Module.&nbsp; In a PSM1 file, a variable, $psScriptRoot exits.&nbsp; This is the path where the module is installed.&nbsp; 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.&nbsp; This way, each function is easy to locate because it is in it&#8217;s own file, but you can still import them all as a group.&nbsp; Remember, however, that since PowerShell is an interpreted language, you&#8217;ll need to import the functions in order.&nbsp; Right now, it doesn&#8217;t matter, because Get-Listbox doesn&#8217;t have anything to do with Show-Control yet.<\/p>\n<p>In this module, I&#8217;ll start with the following lines<\/p>\n<p>. $psScriptRoot\\Get-Listbox.ps1<\/p>\n<p>. $psScriptRoot\\Show-Control.ps1<\/p>\n<p>Since this series is starting to have a little too much inline code, this time I&#8217;m attaching the scripts.&nbsp; Get-Listbox will return you a listbox from an enumerated type, an existing type, or a list of strings.&nbsp; Load them into your runspace by typing &#8220;Add-Module Control&#8221;.&nbsp; When you&#8217;re done, you might want to add the functions below to the module.<\/p>\n<p>I can easily turn Get-Listbox into Select-Listbox, which will display the control and emit the item the user picked onto the pipeline.<\/p>\n<p>See:<\/p>\n<p>function Select-Listbox() { <br \/>&nbsp;&nbsp; if ($input) { <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $listBox = $input | Get-Listbox <br \/>&nbsp;&nbsp; } else { <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $listBox = $args&nbsp; | Get-Listbox <br \/>&nbsp;&nbsp; }&nbsp;&nbsp; <br \/>&nbsp;&nbsp; $listBox | Show-Control @{ <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;Window.Closed&#8221; = {$window.Tag = $window.Content.SelectedItem} <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;MouseDoubleClick&#8221; = {$window.Close()} <br \/>&nbsp;&nbsp; } <br \/>}<\/p>\n<p>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<\/p>\n<p>function Get-HistoryListbox() { <br \/>&nbsp;&nbsp;&nbsp; Get-History | % { $_.CommandLine } | Get-Listbox <br \/>}<\/p>\n<p>function Select-History() { <br \/>&nbsp;&nbsp; Get-History | % { $_.CommandLine } | Select-Listbox <br \/>}<\/p>\n<p>function Invoke-History() { <br \/>&nbsp;&nbsp; Select-History | Invoke-Expression <br \/>}<\/p>\n<p>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&nbsp; You can find more information about it <a title=\"HERE\" href=\"http:\/\/huddledmasses.org\/wpf-from-powershell-select-grid\/\">HERE<\/a>.<\/p>\n<p>Let&#8217;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.<\/p>\n<p>function Get-VideoPlayer($file) { <br \/>&nbsp;&nbsp;&nbsp; $mediaPlayer = New-Object Windows.Controls.MediaElement <br \/>&nbsp;&nbsp;&nbsp; $mediaPlayer.Source = New-Object System.URI (Resolve-Path $file) <br \/>&nbsp;&nbsp;&nbsp; $mediaPlayer.LoadedBehavior = &#8220;Manual&#8221; <br \/>&nbsp;&nbsp;&nbsp; $mediaPlayer <br \/>}<\/p>\n<p>Now lets build a basic Show-Video:<\/p>\n<p>function Show-Video($file) { <br \/>&nbsp;&nbsp;&nbsp; $videoPlayer = Get-VideoPlayer $file <br \/>&nbsp;&nbsp;&nbsp; $videoPlayer.AllowDrop =$true <br \/>&nbsp;&nbsp;&nbsp; $videoPlayer | Show-Control @{ <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;Drop&#8221;={ <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $this.Source = New-Object System.URI ($_.Data.GetFileDropList() | select -first 1) <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $this.Play() <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;Window.Activated&#8221; = {$window.Content.Play() } <br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;Window.Closed&#8221;={$window.Content.Stop()} <br \/>&nbsp;&nbsp;&nbsp; } <br \/>}<\/p>\n<p>Tomorrow, we&#8217;ll take Show-Video and Get-VideoPlayer and turn them into a video player with some controls, and we&#8217;ll show you how to run controls in the background.<\/p>\n<p>Hope this Helps, <br \/>James Brundage [MSFT]<\/p>\n<p><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/MSDNBlogsFS\/prod.evol.blogs.msdn.com\/CommunityServer.Components.PostAttachments\/00\/08\/55\/21\/64\/Show-ControlAndGet-Listbox.zip\">Show-ControlAndGet-Listbox.zip<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>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.&nbsp; Today, I&#8217;ll show you how to [&hellip;]<\/p>\n","protected":false},"author":600,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[248,360],"class_list":["post-6081","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","tag-powershell","tag-wpf"],"acf":[],"blog_post_summary":"<p>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.&nbsp; Today, I&#8217;ll show you how to [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/6081","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/600"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=6081"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/6081\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=6081"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=6081"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=6081"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}