├── Ep1 WPFGUIinTenLines
├── PoSHGUI.ps1
├── PoSHGUIWithActions.ps1
├── TwitterApi.ps1
├── WPFGUIinTenLines
│ └── MainWindow.xaml
└── objects and properties.ps1
├── Ep2 Basic Wizard
├── Basic Wizard
│ ├── Finish.xaml
│ ├── MainWindow.xaml
│ ├── Middle.xaml
│ └── Title.xaml
├── BasicWizard.ps1
└── Get-XamlObject.ps1
├── Ep3 CheckBoxesAndRadioButtons
├── CheckBoxesAndRadioButons.ps1
├── CheckBoxesAndRadioButtons
│ ├── Finish.xaml
│ ├── MainWindow.xaml
│ ├── Middle.xaml
│ └── Title.xaml
└── EventObjectExplore.ps1
├── Ep4 Enable Disable Hide and Collapse
├── EnableDisableHideCollapse.ps1
└── Ep4 Enable Disable Hide and Collapse
│ ├── Finish.xaml
│ ├── MainWindow.xaml
│ ├── Middle.xaml
│ └── Title.xaml
├── Ep5 3 ways to do IP address boxes
├── Ep5 3 Ways To Do IP Address Boxes
│ ├── Finish.xaml
│ ├── MainWindow.xaml
│ ├── Middle.xaml
│ └── Title.xaml
└── IPAddressBoxes.ps1
├── Ep6 Routed Events
├── Ep6 Routed Events
│ ├── Finish.xaml
│ ├── MainWindow.xaml
│ ├── Middle.xaml
│ └── Title.xaml
└── Routed Events.ps1
├── Ep7 Runspaces
├── DebugRunspace.ps1
├── Ep7 Runspaces
│ ├── Finish.xaml
│ ├── MainWindow.xaml
│ ├── Middle.xaml
│ └── Title.xaml
├── Ep7 Runspaces1.ps1
├── Ep7 Runspaces2.ps1
├── Ep7 Runspaces3.ps1
├── Ep7 Runspaces4.ps1
└── Ep7 Runspaces5.ps1
├── Ep8 Runspaces Pt2
├── DebugRunspacePt2.ps1
├── Ep8 Runspaces Pt2
│ ├── Finish.xaml
│ ├── MainWindow.xaml
│ ├── Middle.xaml
│ └── Title.xaml
└── Ep8 Runspaces1.ps1
├── README.md
└── bubbleuproutedevents.xml
/Ep1 WPFGUIinTenLines/PoSHGUI.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | Author : Jim Moyle @jimmoyle
4 | GitHub : https://github.com/JimMoyle/GUIDemo
5 |
6 | Version 0.0.1
7 | #>
8 |
9 | #Add in the frameworks so that we can create the WPF GUI
10 | Add-Type -AssemblyName presentationframework, presentationcore
11 |
12 |
13 | #Create empty hashtable into which we will place the GUI objects
14 | $wpf = @{ }
15 |
16 |
17 | #Grab the content of the Visual Studio xaml file as a string
18 | $inputXML = Get-Content -Path ".\WPFGUIinTenLines\MainWindow.xaml"
19 |
20 | Clear-Host
21 | $inputXML
22 |
23 | Clear-Host
24 | $firstItem = $inputXML | select-object -first 1
25 | $firstItem.gettype().Fullname
26 |
27 |
28 | #clean up xml there is syntax which Visual Studio 2015 creates which PoSH can't understand
29 | $inputXMLClean = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace 'x:Class=".*?"','' -replace 'd:DesignHeight="\d*?"','' -replace 'd:DesignWidth="\d*?"',''
30 |
31 | Clear-Host
32 | $inputXMLClean
33 |
34 |
35 | #change string variable into xml
36 | [xml]$xaml = $inputXMLClean
37 |
38 | Clear-Host
39 | $xaml.GetType().Fullname
40 |
41 |
42 | #read xml data into xaml node reader object
43 | $reader = New-Object System.Xml.XmlNodeReader $xaml
44 |
45 | #create System.Windows.Window object
46 | $tempform = [Windows.Markup.XamlReader]::Load($reader)
47 | $tempform.GetType().Fullname
48 |
49 | #select each named node using an Xpath expression.
50 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
51 |
52 |
53 | #add all the named nodes as members to the $wpf variable, this also adds in the correct type for the objects.
54 | $namedNodes | ForEach-Object {
55 |
56 | $wpf.Add($_.Name, $tempform.FindName($_.Name))
57 |
58 | }
59 |
60 |
61 | #show what's inside $wpf
62 | clear-Host
63 | $wpf
64 |
65 | Clear-Host
66 | $wpf.YouTubeButton.GetType().Fullname
67 |
68 | Clear-Host
69 | $wpf.YouTubeButton
70 |
71 | Clear-Host
72 | $wpf.YouTubeButton.Content
73 |
74 | Clear-Host
75 | $buttonEvents = $wpf.YouTubeButton | Get-Member | Where-Object {$_.MemberType -eq 'Event'}
76 | $buttonEvents.count
77 |
78 |
79 | $wpf.YouTubeWindow.ShowDialog() | Out-Null
--------------------------------------------------------------------------------
/Ep1 WPFGUIinTenLines/PoSHGUIWithActions.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | Author : Jim Moyle @jimmoyle
4 | GitHub : https://github.com/JimMoyle/GUIDemo
5 |
6 | Version 0.0.1
7 | #>
8 |
9 |
10 | #========================================================
11 | #code from previous script
12 | #========================================================
13 |
14 |
15 | Add-Type -AssemblyName presentationframework, presentationcore
16 | $wpf = @{ }
17 | $inputXML = Get-Content -Path ".\WPFGUIinTenLines\MainWindow.xaml"
18 | $inputXMLClean = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace 'x:Class=".*?"','' -replace 'd:DesignHeight="\d*?"','' -replace 'd:DesignWidth="\d*?"',''
19 | [xml]$xaml = $inputXMLClean
20 | $reader = New-Object System.Xml.XmlNodeReader $xaml
21 | $tempform = [Windows.Markup.XamlReader]::Load($reader)
22 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
23 | $namedNodes | ForEach-Object {$wpf.Add($_.Name, $tempform.FindName($_.Name))}
24 |
25 |
26 | #========================================================
27 |
28 |
29 |
30 | #========================================================
31 | #Your Code goes here
32 | #========================================================
33 |
34 | #Import Twitter Module
35 | Import-Module InvokeTwitterAPIs
36 |
37 | #This code runs when the button is clicked
38 | $wpf.YouTubeButton.add_Click({
39 |
40 | #Get screen name from textbox
41 | $screenName = $wpf.YouTubetextBox.text
42 |
43 | #Get Userdata from Twitter
44 | $userdata = Get-TwitterUser_Lookup -screen_name $screenName
45 |
46 | #Show user image in GUI
47 | $wpf.YouTubeimage.source = $userdata.profile_image_url
48 |
49 | })
50 |
51 | #=======================================================
52 | #End of Your Code
53 | #=======================================================
54 |
55 |
56 |
57 | $wpf.YouTubeWindow.ShowDialog() | Out-Null
--------------------------------------------------------------------------------
/Ep1 WPFGUIinTenLines/TwitterApi.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | Author : Jim Moyle @jimmoyle
4 | GitHub : https://github.com/JimMoyle/GUIDemo
5 |
6 | Version 0.0.1
7 | #>
8 |
9 | Find-module *twitter*
10 |
11 | #import the twitter API module after downloading it from the gallery
12 | Import-Module InvokeTwitterAPIs
13 |
14 | #Show twitter oath dev page
15 | Start-process https://dev.twitter.com/oauth
16 |
17 |
18 | #check it is there
19 | Get-Command -Module InvokeTwitterAPIs
20 |
21 |
22 | #Set screenName variable to the user you want to look up
23 | $screenName = 'JimMoyle'
24 |
25 |
26 | #Test username lookup
27 | $userdata = Get-TwitterUser_Lookup -screen_name $screenName
28 | $userdata
29 | $userdata.location
30 |
31 |
32 | #Test location of profile pic
33 | $url = $userdata.profile_image_url
34 | Start-Process $url
--------------------------------------------------------------------------------
/Ep1 WPFGUIinTenLines/WPFGUIinTenLines/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Ep1 WPFGUIinTenLines/objects and properties.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | Author : Jim Moyle @jimmoyle
4 | GitHub : https://github.com/JimMoyle/GUIDemo
5 |
6 | Version 0.0.1
7 | #>
8 |
9 | #create a file object by listing the contents of a directory
10 | $fileObject = Get-ChildItem c:\GUIDemo
11 | $fileObject
12 |
13 | #show what that object is made from
14 | $fileObject.GetType().name
15 |
16 |
17 | #show the directory property
18 | $fileObject.Directory
19 |
20 |
21 | #copy the file using its method
22 | $fileObject.CopyTo('C:\GUIDemo\CopyTarget.txt')
23 |
24 |
25 | #show that there is now 2 files
26 | Get-ChildItem c:\GUIDemo
--------------------------------------------------------------------------------
/Ep2 Basic Wizard/Basic Wizard/Finish.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Ep2 Basic Wizard/Basic Wizard/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Ep2 Basic Wizard/Basic Wizard/Middle.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Ep2 Basic Wizard/Basic Wizard/Title.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Ep2 Basic Wizard/BasicWizard.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 27/01/2017
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 |
13 | function Get-XamlObject
14 | {
15 | [CmdletBinding()]
16 | param (
17 | [Parameter(Position = 0,
18 | Mandatory = $true,
19 | ValuefromPipelineByPropertyName = $true,
20 | ValuefromPipeline = $true)]
21 | [Alias("FullName")]
22 | [System.String[]]$Path
23 | )
24 |
25 | BEGIN
26 | {
27 | Set-StrictMode -Version Latest
28 |
29 | $wpfObjects = @{ }
30 | Add-Type -AssemblyName presentationframework, presentationcore
31 |
32 | } #BEGIN
33 |
34 | PROCESS
35 | {
36 | try
37 | {
38 | foreach ($xamlFile in $Path)
39 | {
40 | #Change content of Xaml file to be a set of powershell GUI objects
41 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
42 | $inputXMLClean = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
43 | [xml]$xaml = $inputXMLClean
44 | $reader = New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop
45 | $tempform = [Windows.Markup.XamlReader]::Load($reader)
46 |
47 | #Grab named objects from tree and put in a flat structure
48 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
49 | $namedNodes | ForEach-Object {
50 |
51 | $wpfObjects.Add($_.Name, $tempform.FindName($_.Name))
52 |
53 | } #foreach-object
54 | } #foreach xamlpath
55 | } #try
56 | catch
57 | {
58 | throw $error[0]
59 | } #catch
60 | } #PROCESS
61 |
62 | END
63 | {
64 | Write-Output $wpfObjects
65 | } #END
66 | }
67 |
68 | #region Blah
69 | $path = 'E:\JimM\Dropbox\Dropbox (Personal)\ScriptScratch\YouTube\Ep2 Basic Wizard\Basic Wizard'
70 |
71 | $wpf = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
72 |
73 | #endregion
74 |
75 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage) | Out-Null
76 |
77 | $wpf.titleButtonNext.add_Click({
78 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
79 | })
80 |
81 | $wpf.middleButtonNext.add_Click({
82 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.FinishPage)
83 | })
84 |
85 | $wpf.middleButtonBack.add_Click({
86 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage)
87 | })
88 |
89 | $wpf.FinishButtonBack.add_Click({
90 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
91 | })
92 |
93 | $wpf.WizardWindow.Showdialog() | Out-Null
--------------------------------------------------------------------------------
/Ep2 Basic Wizard/Get-XamlObject.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 24/01/2017 16:13
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 |
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
--------------------------------------------------------------------------------
/Ep3 CheckBoxesAndRadioButtons/CheckBoxesAndRadioButons.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 27/01/2017
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 | #region Episode 2 code
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
63 |
64 | $path = '.\CheckBoxesAndRadioButtons'
65 |
66 | $wpf = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
67 |
68 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage) | Out-Null
69 |
70 | $wpf.titleButtonNext.add_Click({
71 |
72 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
73 | })
74 |
75 | $wpf.middleButtonNext.add_Click({
76 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.FinishPage)
77 | })
78 |
79 | $wpf.middleButtonBack.add_Click({
80 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage)
81 | })
82 |
83 | $wpf.FinishButtonBack.add_Click({
84 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
85 | })
86 | #endregion
87 |
88 | #region RadioButton
89 | $wpf.RadioButton.add_Checked({
90 |
91 | #$this | Export-Clixml "$path\this.xml"
92 | #$_ | Export-Clixml "$path\DollarUnderscore.xml"
93 |
94 | $wpf.FinishTextBlockHypervisor.text = $this.content
95 |
96 | })
97 |
98 | $wpf.RadioButton1.add_Checked({
99 |
100 | $wpf.FinishTextBlockHypervisor.text = $this.content
101 |
102 | })
103 |
104 | $wpf.RadioButton2.add_Checked({
105 |
106 | $wpf.FinishTextBlockHypervisor.text = $this.content
107 |
108 | })
109 |
110 | $wpf.RadioButton3.add_Checked({
111 |
112 | $wpf.FinishTextBlockHypervisor.text = $this.content
113 |
114 | })
115 |
116 | #endregion
117 |
118 | #region Checkboxes
119 | $wpf.CheckBox.add_Checked({
120 |
121 | $wpf.FinishTextBlockCPU.text = $this.content
122 |
123 | })
124 |
125 | $wpf.CheckBox.add_UnChecked({
126 |
127 | $wpf.FinishTextBlockCPU.text = ''
128 |
129 | })
130 |
131 | $wpf.CheckBox1.add_Checked({
132 |
133 | $wpf.FinishTextBlockMemory.text = $this.content
134 |
135 | })
136 |
137 | $wpf.CheckBox1.add_UnChecked({
138 |
139 | $wpf.FinishTextBlockMemory.text = ''
140 |
141 | })
142 |
143 | $wpf.CheckBox2.add_Checked({
144 |
145 | $wpf.FinishTextBlockDisk.text = $this.content
146 |
147 | })
148 |
149 | $wpf.CheckBox2.add_UnChecked({
150 |
151 | $wpf.FinishTextBlockDisk.text = ''
152 |
153 | })
154 |
155 |
156 | #endregion
157 |
158 | #region defaults
159 | $wpf.FinishTextBlockHypervisor.text = $wpf.RadioButton.Content
160 | #endregion
161 |
162 | $wpf.Window.Showdialog() | Out-Null
--------------------------------------------------------------------------------
/Ep3 CheckBoxesAndRadioButtons/CheckBoxesAndRadioButtons/Finish.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Ep3 CheckBoxesAndRadioButtons/CheckBoxesAndRadioButtons/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Ep3 CheckBoxesAndRadioButtons/CheckBoxesAndRadioButtons/Middle.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Ep3 CheckBoxesAndRadioButtons/CheckBoxesAndRadioButtons/Title.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Ep3 CheckBoxesAndRadioButtons/EventObjectExplore.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 27/01/2017
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 |
13 | $thisxml = import-clixml -Path "E:\JimM\Dropbox\Dropbox (Personal)\ScriptScratch\YouTube\Ep3 CheckBoxesAndRadioButtons\CheckBoxesAndRadioButtons\this.xml"
14 |
15 | $du = import-clixml -Path "E:\JimM\Dropbox\Dropbox (Personal)\ScriptScratch\YouTube\Ep3 CheckBoxesAndRadioButtons\CheckBoxesAndRadioButtons\\DollarUnderscore.xml"
16 |
17 | $thisxml # GUI item properties
18 |
19 | $thisxml.Content
20 |
21 | $thisxml.Parent.Name
22 |
23 | $thisxml.Parent.Children
24 |
25 | $du #Event Properties
--------------------------------------------------------------------------------
/Ep4 Enable Disable Hide and Collapse/EnableDisableHideCollapse.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 27/01/2017
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 | #region Episode 2 code
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
63 |
64 | $path = '.\Ep4 Enable Disable Hide and Collapse'
65 |
66 | $wpf = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
67 |
68 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage) | Out-Null
69 |
70 | $wpf.titleButtonNext.add_Click({
71 |
72 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
73 | })
74 |
75 | $wpf.middleButtonNext.add_Click({
76 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.FinishPage)
77 | })
78 |
79 | $wpf.middleButtonBack.add_Click({
80 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage)
81 | })
82 |
83 | $wpf.FinishButtonBack.add_Click({
84 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
85 | })
86 | #endregion
87 |
88 | #region RadioButton
89 | $wpf.RadioButton.add_Checked({
90 | $wpf.FinishTextBlockHypervisor.text = $this.content
91 | })
92 |
93 | $wpf.RadioButton1.add_Checked({
94 | $wpf.FinishTextBlockHypervisor.text = $this.content
95 | })
96 |
97 | $wpf.RadioButton2.add_Checked({
98 | $wpf.FinishTextBlockHypervisor.text = $this.content
99 | })
100 |
101 | $wpf.RadioButton3.add_Checked({
102 | $wpf.FinishTextBlockHypervisor.text = $this.content
103 | })
104 |
105 | #endregion
106 |
107 | $wpf.TitleCheckBox.add_Checked({
108 |
109 | $wpf.titleButtonNext.IsEnabled = $true
110 |
111 | })
112 |
113 | $wpf.TitleCheckBox.add_UnChecked({
114 |
115 | $wpf.titleButtonNext.IsEnabled = $false
116 |
117 | })
118 |
119 | [PSCustomObject]$resourceTest = @{
120 | CPU = $false
121 | Memory = $false
122 | Disk = $false
123 | }
124 |
125 | $wpf.CheckBoxCPU.add_Checked({
126 |
127 | $wpf.FinishTextBlockCPU.Visibility = 'Visible'
128 | $wpf.MiddleButtonNext.IsEnabled = $true
129 | $resourceTest.CPU = $true
130 | })
131 |
132 | $wpf.CheckBoxCPU.add_UnChecked({
133 |
134 | $wpf.FinishTextBlockCPU.Visibility = 'Collapsed'
135 | $resourceTest.CPU = $false
136 | if (-not($resourceTest.values -contains $true)){
137 |
138 | $wpf.MiddleButtonNext.IsEnabled = $false
139 | }
140 | })
141 |
142 | $wpf.CheckBoxMemory.add_Checked({
143 |
144 | $wpf.FinishTextBlockMemory.Visibility = 'Visible'
145 | $wpf.MiddleButtonNext.IsEnabled = $true
146 | $resourceTest.Memory = $true
147 | })
148 |
149 | $wpf.CheckBoxMemory.add_UnChecked({
150 |
151 | $wpf.FinishTextBlockMemory.Visibility = 'Collapsed'
152 | $resourceTest.Memory = $false
153 | if (-not($resourceTest.values -contains $true)){
154 |
155 | $wpf.MiddleButtonNext.IsEnabled = $false
156 | }
157 | })
158 |
159 | $wpf.CheckBoxDisk.add_Checked({
160 |
161 | $wpf.FinishTextBlockDisk.Visibility = 'Visible'
162 | $wpf.MiddleButtonNext.IsEnabled = $true
163 | $resourceTest.Disk = $true
164 | })
165 |
166 | $wpf.CheckBoxDisk.add_UnChecked({
167 |
168 | $wpf.FinishTextBlockDisk.Visibility = 'Collapsed'
169 | $resourceTest.Disk = $false
170 | if (-not($resourceTest.values -contains $true)){
171 |
172 | $wpf.MiddleButtonNext.IsEnabled = $false
173 | }
174 |
175 | })
176 |
177 |
178 |
179 |
180 |
181 | $wpf.FinishTextBlockHypervisor.text = $wpf.RadioButton.Content
182 |
183 | $wpf.Window.Showdialog() | Out-Null #Start Application
--------------------------------------------------------------------------------
/Ep4 Enable Disable Hide and Collapse/Ep4 Enable Disable Hide and Collapse/Finish.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Ep4 Enable Disable Hide and Collapse/Ep4 Enable Disable Hide and Collapse/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Ep4 Enable Disable Hide and Collapse/Ep4 Enable Disable Hide and Collapse/Middle.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Ep4 Enable Disable Hide and Collapse/Ep4 Enable Disable Hide and Collapse/Title.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Ep5 3 ways to do IP address boxes/Ep5 3 Ways To Do IP Address Boxes/Finish.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Ep5 3 ways to do IP address boxes/Ep5 3 Ways To Do IP Address Boxes/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Ep5 3 ways to do IP address boxes/Ep5 3 Ways To Do IP Address Boxes/Middle.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Ep5 3 ways to do IP address boxes/Ep5 3 Ways To Do IP Address Boxes/Title.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Ep5 3 ways to do IP address boxes/IPAddressBoxes.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 27/01/2017
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 | #region Episode 2 code
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
63 |
64 | $path = "C:\Users\Jim\Dropbox (Personal)\ScriptScratch\YouTube\Ep5 3 ways to do IP address boxes\Ep5 3 Ways To Do IP Address Boxes"
65 |
66 | $wpf = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
67 |
68 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage) | Out-Null
69 |
70 | $wpf.titleButtonNext.add_Click({
71 |
72 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
73 | })
74 |
75 | $wpf.middleButtonNext.add_Click({
76 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.FinishPage)
77 | })
78 |
79 | $wpf.middleButtonBack.add_Click({
80 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage)
81 | })
82 |
83 | $wpf.FinishButtonBack.add_Click({
84 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
85 | })
86 | #endregion
87 |
88 | #Title Regex Box Code
89 | $wpf.TitleTextBox.Add_TextChanged({
90 |
91 | #Regex from Sapien Power Regex
92 | $ipRegex = '^\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b$'
93 |
94 | if($wpf.TitleTextBox.text -match $ipRegex){
95 | $wpf.TitleBorder.BorderBrush = 'gray'
96 | }
97 | else{
98 | $wpf.TitleBorder.BorderBrush = 'red'
99 | }
100 |
101 | })
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | #Middle Cast Test code
110 | function Test-IP{
111 | param (
112 | $ipaddress
113 | )
114 |
115 | try
116 | {
117 | $ipaddress = [ipaddress]$ipaddress
118 | return $true
119 | }
120 | catch
121 | {
122 | return $false
123 | }
124 | }
125 |
126 | $wpf.MiddleTextBox.Add_TextChanged({
127 |
128 | if($this.text -match $simpleRegex -and (Test-IP -ipaddress $($this.text))){
129 | $wpf.MiddleBorder.BorderBrush = 'gray'
130 |
131 | }
132 | else{
133 | $wpf.MiddleBorder.BorderBrush = 'red'
134 |
135 | }
136 |
137 | })
138 |
139 | [regex]$simpleRegex = '\d+\.\d+\.\d+\.\d+'
140 | # $this.text -match $simpleRegex -and (Test-IP -ipaddress $($this.text))
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | function Set-IpBoxBehaviour{
150 |
151 | param(
152 | $OctetEvent
153 | )
154 |
155 | #Grab content of the textbox
156 | $octet = $OctetEvent.OriginalSource.text
157 |
158 | #If Octet doesn't match numbers or dot replace other characters with nothing
159 | if ($octet -match '([^\d|\.])')
160 | {
161 | $badChar = $matches[1]
162 | $octet = $octet.Replace($badChar, '')
163 | $OctetEvent.OriginalSource.CaretIndex = 3
164 | }
165 |
166 | #As long as you aren't in last box then enforce movement to next box under correct conditions
167 | if (-not ($OctetEvent.OriginalSource.Name -like "*4*")){
168 | if (($octet -like '*.*' -or $octet.Length -eq 3) -and $octet.Length -gt 1)
169 | {
170 | #setup direction object (default value is next so no need to set it)
171 | $directionNext = new-object System.Windows.Input.FocusNavigationDirection
172 | #setup traversal object with Next as input
173 | $requestNext = new-object System.Windows.Input.TraversalRequest $directionNext
174 | #move focus requires a System.Windows.Input.TraversalRequest object as parameter to change focus to nect object
175 | $OctetEvent.OriginalSource.MoveFocus($requestNext)
176 |
177 | }
178 | }
179 |
180 | #remove dot from text if it's there
181 | $octet = $octet.Replace('.', '')
182 |
183 | #turn border red if value is > 255
184 | if ([int]$octet -gt 255)
185 | {
186 | $stack = [Windows.Media.VisualTreeHelper]::GetParent($OctetEvent.OriginalSource)
187 | $border = [Windows.Media.VisualTreeHelper]::GetParent($stack)
188 | $border.BorderBrush = 'red'
189 | }
190 |
191 | #Walk visual tree to find Border from textbox
192 | $stack = [Windows.Media.VisualTreeHelper]::GetParent($OctetEvent.OriginalSource)
193 | $border = [Windows.Media.VisualTreeHelper]::GetParent($stack)
194 | $currentBorderBrush = $border.BorderBrush
195 |
196 | #check if any of the other octets are simultaneously errored before turning border back to gray
197 | if ([int]$octet -le 255 -and $currentBorderBrush.color -eq '#FFFF0000')
198 | {
199 | #get all child textboxes from stack panel
200 | $children = $stack.Children
201 |
202 | #Include only ones from list which have data
203 | $childrenoct = $children | where-object { $_.Name -like "*oct*" -and $_.text -ne '' }
204 |
205 | if ($childrenoct.count -ge 1)
206 | {
207 |
208 | $childrenoct | ForEach-Object {
209 |
210 | $value = $_.text
211 | if ([int]$value -gt 255)
212 | {
213 | $addValue = 1
214 | $totalValue += $addValue
215 | }
216 |
217 | }
218 | }
219 | if ($totalValue -gt 0)
220 | {
221 | $border.BorderBrush = 'red'
222 | }
223 | else
224 | {
225 | $border.BorderBrush = 'gray'
226 | }
227 |
228 | }
229 |
230 | #As we have changed the text from what was entered, we now need to set the textbox to the correct txt
231 | if (-not ($OctetEvent.OriginalSource.text -eq $octet))
232 | {
233 | $OctetEvent.OriginalSource.text = $octet
234 | $OctetEvent.OriginalSource.CaretIndex = 3
235 | }
236 | }
237 |
238 | $wpf.textBoxManIPOct1.Add_TextChanged({
239 | Set-IpBoxBehaviour -OctetEvent $_
240 | })
241 |
242 | $wpf.textBoxManIPOct2.Add_TextChanged({
243 | Set-IpBoxBehaviour -OctetEvent $_
244 | })
245 |
246 | $wpf.textBoxManIPOct3.Add_TextChanged({
247 | Set-IpBoxBehaviour -OctetEvent $_
248 | })
249 |
250 | $wpf.textBoxManIPOct4.Add_TextChanged({
251 | Set-IpBoxBehaviour -OctetEvent $_
252 | })
253 |
254 | #create direction object
255 | $directionPrevious = new-object System.Windows.Input.FocusNavigationDirection
256 | #set direction to back
257 | $directionPrevious.value__ = 1
258 | #create direction request
259 | $requestPrevious = new-object System.Windows.Input.TraversalRequest $directionPrevious
260 |
261 | $wpf.textBoxManIPOct2.add_PreviewKeyDown({ if ($_.key -eq 'Back' -and $this.CaretIndex -eq 0) { $this.MoveFocus($requestPrevious) } })
262 | $wpf.textBoxManIPOct3.add_PreviewKeyDown({ if ($_.key -eq 'Back' -and $this.CaretIndex -eq 0) { $this.MoveFocus($requestPrevious) } })
263 | $wpf.textBoxManIPOct4.add_PreviewKeyDown({ if ($_.key -eq 'Back' -and $this.CaretIndex -eq 0) { $this.MoveFocus($requestPrevious) } })
264 |
265 |
266 | $wpf.Window.Showdialog() | Out-Null #Start Application
267 |
--------------------------------------------------------------------------------
/Ep6 Routed Events/Ep6 Routed Events/Finish.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/Ep6 Routed Events/Ep6 Routed Events/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Ep6 Routed Events/Ep6 Routed Events/Middle.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Ep6 Routed Events/Ep6 Routed Events/Title.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Ep6 Routed Events/Routed Events.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 2017/03/10
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 | #region Episode 2 code
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
63 |
64 | $path = "E:\JimM\Dropbox\Dropbox (Personal)\ScriptScratch\YouTube\Ep6 Routed Events\Ep6 Routed Events"
65 |
66 | $wpf = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
67 |
68 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage) | Out-Null
69 |
70 | $wpf.titleButtonNext.add_Click({
71 |
72 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.FinishPage)
73 | })
74 |
75 | $wpf.middleButtonNext.add_Click({
76 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.FinishPage)
77 | })
78 |
79 | $wpf.middleButtonBack.add_Click({
80 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage)
81 | })
82 |
83 | $wpf.FinishButtonBack.add_Click({
84 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
85 | })
86 | #endregion
87 | function Set-IpBoxBehaviour{
88 |
89 | param(
90 | $OctetEvent
91 | )
92 |
93 | #Grab content of the textbox
94 | $octet = $OctetEvent.OriginalSource.text
95 |
96 | #If Octet doesn't match numbers or dot replace other characters with nothing
97 | if ($octet -match '([^\d|\.])')
98 | {
99 | $badChar = $matches[1]
100 | $octet = $octet.Replace($badChar, '')
101 | $OctetEvent.OriginalSource.CaretIndex = 3
102 | }
103 |
104 | #As long as you aren't in last box then enforce movement to next box under correct conditions
105 | if (-not ($OctetEvent.OriginalSource.Name -like "*4*")){
106 | if (($octet -like '*.*' -or $octet.Length -eq 3) -and $octet.Length -gt 1)
107 | {
108 | #setup direction object (default value is next so no need to set it)
109 | $directionNext = new-object System.Windows.Input.FocusNavigationDirection
110 | #setup traversal object with Next as input
111 | $requestNext = new-object System.Windows.Input.TraversalRequest $directionNext
112 | #move focus requires a System.Windows.Input.TraversalRequest object as parameter to change focus to nect object
113 | $OctetEvent.OriginalSource.MoveFocus($requestNext)
114 |
115 | }
116 | }
117 |
118 | #remove dot from text if it's there
119 | $octet = $octet.Replace('.', '')
120 |
121 | #turn border red if value is > 255
122 | if ([int]$octet -gt 255)
123 | {
124 | $stack = [Windows.Media.VisualTreeHelper]::GetParent($OctetEvent.OriginalSource)
125 | $border = [Windows.Media.VisualTreeHelper]::GetParent($stack)
126 | $border.BorderBrush = 'red'
127 | }
128 |
129 | #Walk visual tree to find Border from textbox
130 | $stack = [Windows.Media.VisualTreeHelper]::GetParent($OctetEvent.OriginalSource)
131 | $border = [Windows.Media.VisualTreeHelper]::GetParent($stack)
132 | $currentBorderBrush = $border.BorderBrush
133 |
134 | #check if any of the other octets are simultaneously errored before turning border back to gray
135 | if ([int]$octet -le 255 -and $currentBorderBrush.color -eq '#FFFF0000')
136 | {
137 | #get all child textboxes from stack panel
138 | $children = $stack.Children
139 |
140 | #Include only ones from list which have data
141 | $childrenoct = $children | where-object { $_.Name -like "*oct*" -and $_.text -ne '' }
142 |
143 | if ($childrenoct.count -ge 1)
144 | {
145 |
146 | $childrenoct | ForEach-Object {
147 |
148 | $value = $_.text
149 | if ([int]$value -gt 255)
150 | {
151 | $addValue = 1
152 | $totalValue += $addValue
153 | }
154 |
155 | }
156 | }
157 | if ($totalValue -gt 0)
158 | {
159 | $border.BorderBrush = 'red'
160 | }
161 | else
162 | {
163 | $border.BorderBrush = 'gray'
164 | }
165 |
166 | }
167 |
168 | #As we have changed the text from what was entered, we now need to set the textbox to the correct txt
169 | if (-not ($OctetEvent.OriginalSource.text -eq $octet))
170 | {
171 | $OctetEvent.OriginalSource.text = $octet
172 | $OctetEvent.OriginalSource.CaretIndex = 3
173 | }
174 | } # Episode 5
175 |
176 |
177 | #Create 'Local' Event for Button one
178 |
179 | $wpf.buttonOne.add_Click({
180 |
181 | #Write-Host 'One'
182 |
183 | Write-Host "Local $($_.OriginalSource.Content)"
184 |
185 | $_.Handled = $true
186 |
187 | })
188 |
189 |
190 |
191 | #[Windows.EventManager]::GetRoutedEvents() | Where-Object { $_.RoutingStrategy -eq “Bubble”} | Sort-Object Name
192 |
193 |
194 |
195 |
196 |
197 |
198 | #Create Routed event for Button Click attached to Border
199 |
200 | [System.Windows.RoutedEventHandler]$clickHandler = {
201 |
202 | write-host "Routed $($_.OriginalSource.Content)"
203 | }
204 |
205 | $wpf.titleBorder.AddHandler([System.Windows.Controls.Button]::ClickEvent, $clickHandler)
206 |
207 |
208 |
209 |
210 |
211 | #Add Routed event for Textbox Text Changed attached to Page
212 |
213 | [System.Windows.RoutedEventHandler]$textChangedHandler = {
214 |
215 | Set-IpBoxBehaviour -OctetEvent $_
216 | }
217 |
218 | $wpf.FinishPage.AddHandler([System.Windows.Controls.TextBox]::TextChangedEvent, $textChangedHandler)
219 |
220 |
221 |
222 | #[Windows.EventManager]::GetRoutedEvents() | Where-Object { $_.RoutingStrategy -eq “Tunnel”} | Sort-Object Name
223 |
224 |
225 | #Get list of text boxes where we want to implement unrouted event (be careful as this is looking for all textboxes!)
226 | $textBoxes = $wpf.Values | Where-Object {$_ -is [System.Windows.Controls.TextBox] -and $_.IsReadOnly -eq $false -and $_.name -notlike "*1*" } | Select-Object -ExpandProperty Name
227 |
228 | #setup direction object
229 | $directionPrevious = new-object System.Windows.Input.FocusNavigationDirection
230 | #set direction to back
231 | $directionPrevious.value__ = 1
232 | #setup traversal object with Next as input
233 | $requestPrevious = new-object System.Windows.Input.TraversalRequest $directionPrevious
234 | #move focus requires a System.Windows.Input.TraversalRequest object as parameter to 'tab' to next object
235 |
236 | #Set up Event for all textboxes in list
237 | foreach ($box in $textboxes){
238 |
239 | $wpf.$box.add_PreviewKeyDown({
240 | if ($_.key -eq 'Back' -and $this.CaretIndex -eq 0) {
241 | $this.MoveFocus($requestPrevious)
242 | }
243 | })
244 | }
245 |
246 | $wpf.Window.ShowDialog() | Out-Null
--------------------------------------------------------------------------------
/Ep7 Runspaces/DebugRunspace.ps1:
--------------------------------------------------------------------------------
1 | #Find PoSH process with the correct 'window title'
2 | Get-PSHostProcessInfo | Where-Object {$_.MainWindowTitle -eq 'MainWindow'} | Enter-PSHostProcess
3 |
4 | #Enter the runspace which is waiting for a debugger
5 | Get-Runspace | Where-Object {$_.Debugger.InBreakpoint -eq $true} | Debug-Runspace
--------------------------------------------------------------------------------
/Ep7 Runspaces/Ep7 Runspaces/Finish.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Ep7 Runspaces/Ep7 Runspaces/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Ep7 Runspaces/Ep7 Runspaces/Middle.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Ep7 Runspaces/Ep7 Runspaces/Title.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Ep7 Runspaces/Ep7 Runspaces1.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 2017/03/27
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 | #region Episode 2 code
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
63 |
64 | $path = Join-Path $PSScriptRoot '\Ep7 Runspaces'
65 |
66 | $wpf = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
67 |
68 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage) | Out-Null
69 |
70 | $wpf.titleButtonNext.add_Click({
71 |
72 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
73 | })
74 |
75 | $wpf.middleButtonNext.add_Click({
76 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.FinishPage)
77 | })
78 |
79 | $wpf.middleButtonBack.add_Click({
80 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage)
81 | })
82 |
83 | $wpf.FinishButtonBack.add_Click({
84 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
85 | })
86 | #endregion
87 |
88 |
89 | $wpf.titleButton.add_Click({
90 |
91 | Start-Sleep -Seconds $wpf.titleTextBox.text
92 | $wpf.titleTextBlock.Text = "$($wpf.titleTextBox.text) second sleep finished"
93 | })
94 |
95 | $wpf.Window.ShowDialog() | Out-Null
--------------------------------------------------------------------------------
/Ep7 Runspaces/Ep7 Runspaces2.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 2017/03/27
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 | #region Episode 2 code
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
63 |
64 | $path = Join-Path $PSScriptRoot '\Ep7 Runspaces'
65 |
66 | $wpf = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
67 |
68 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage) | Out-Null
69 |
70 | $wpf.titleButtonNext.add_Click({
71 |
72 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
73 | })
74 |
75 | $wpf.middleButtonNext.add_Click({
76 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.FinishPage)
77 | })
78 |
79 | $wpf.middleButtonBack.add_Click({
80 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.TitlePage)
81 | })
82 |
83 | $wpf.FinishButtonBack.add_Click({
84 | $wpf.WizardWindowFrame.NavigationService.Navigate($wpf.MiddlePage)
85 | })
86 | #endregion
87 |
88 |
89 | $wpf.titleButton.add_Click({
90 |
91 | $runspace = [runspacefactory]::CreateRunspace()
92 | #$runspace | Get-Member
93 | $powerShell = [powershell]::Create()
94 | #$powerShell | Get-Member
95 | $powerShell.runspace = $runspace
96 | $runspace.Open()
97 |
98 | [void]$PowerShell.AddScript({
99 |
100 | Wait-Debugger
101 | Start-Sleep -Seconds $wpf.titleTextBox.text
102 | $wpf.titleTextBlock.Text = "$($wpf.titleTextBox.text) second sleep finished"
103 |
104 | })
105 |
106 | $asyncObject = $PowerShell.BeginInvoke()
107 | })
108 |
109 |
110 | $wpf.Window.ShowDialog() | Out-Null
--------------------------------------------------------------------------------
/Ep7 Runspaces/Ep7 Runspaces3.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 2017/03/27
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 | #region Episode 2 code
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
63 |
64 | $path = Join-Path $PSScriptRoot '\Ep7 Runspaces'
65 |
66 | $script:syncHash = [hashtable]::Synchronized(@{ })
67 |
68 | $script:syncHash = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
69 |
70 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.TitlePage) | Out-Null
71 |
72 | $script:syncHash.titleButtonNext.add_Click({
73 |
74 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.MiddlePage)
75 | })
76 |
77 | $script:syncHash.middleButtonNext.add_Click({
78 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.FinishPage)
79 | })
80 |
81 | $script:syncHash.middleButtonBack.add_Click({
82 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.TitlePage)
83 | })
84 |
85 | $script:syncHash.FinishButtonBack.add_Click({
86 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.MiddlePage)
87 | })
88 | #endregion
89 |
90 |
91 | $script:syncHash.titleButton.add_Click({
92 |
93 | $runspace = [runspacefactory]::CreateRunspace()
94 | $powerShell = [powershell]::Create()
95 | $powerShell.runspace = $runspace
96 | $runspace.Open()
97 | $runspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
98 |
99 | [void]$PowerShell.AddScript({
100 |
101 | Wait-Debugger
102 | Start-Sleep -Seconds $script:syncHash.titleTextBox.text
103 | $syncHash.titleTextBlock.Text = "$($syncHash.titleTextBox.text) second sleep finished"
104 |
105 | })
106 |
107 | $asyncObject = $PowerShell.BeginInvoke()
108 |
109 | })
110 |
111 |
112 | $script:syncHash.Window.ShowDialog() | Out-Null
--------------------------------------------------------------------------------
/Ep7 Runspaces/Ep7 Runspaces4.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 2017/03/27
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 | #region Episode 2 code
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
63 |
64 | $path = Join-Path $PSScriptRoot '\Ep7 Runspaces'
65 |
66 | $script:syncHash = [hashtable]::Synchronized(@{ })
67 |
68 | $script:syncHash = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
69 |
70 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.TitlePage) | Out-Null
71 |
72 | $script:syncHash.titleButtonNext.add_Click({
73 |
74 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.MiddlePage)
75 | })
76 |
77 | $script:syncHash.middleButtonNext.add_Click({
78 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.FinishPage)
79 | })
80 |
81 | $script:syncHash.middleButtonBack.add_Click({
82 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.TitlePage)
83 | })
84 |
85 | $script:syncHash.FinishButtonBack.add_Click({
86 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.MiddlePage)
87 | })
88 | #endregion
89 |
90 |
91 | $script:syncHash.titleButton.add_Click({
92 |
93 | $syncHash.sleepSecs = $syncHash.titleTextBox.text
94 |
95 | $runspace = [runspacefactory]::CreateRunspace()
96 | $powerShell = [powershell]::Create()
97 | $powerShell.runspace = $runspace
98 | $runspace.Open()
99 | $runspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
100 |
101 | [void]$PowerShell.AddScript({
102 |
103 | Wait-Debugger
104 | Start-Sleep -Seconds $syncHash.sleepSecs
105 | $syncHash.titleTextBlock.Text = "$($syncHash.sleepSecs) second sleep finished"
106 |
107 | })
108 |
109 | $asyncObject = $PowerShell.BeginInvoke()
110 |
111 | })
112 |
113 |
114 | $script:syncHash.Window.ShowDialog() | Out-Null
--------------------------------------------------------------------------------
/Ep7 Runspaces/Ep7 Runspaces5.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 2017/03/27
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 | #region Episode 2 code
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Change content of Xaml file to be a set of powershell GUI objects
40 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
41 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
42 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
43 |
44 | #Grab named objects from tree and put in a flat structure using Xpath
45 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
46 | $namedNodes | ForEach-Object {
47 | $output.Add($_.Name, $tempform.FindName($_.Name))
48 | } #foreach-object
49 | } #foreach xamlpath
50 | } #try
51 | catch
52 | {
53 | throw $error[0]
54 | } #catch
55 | } #PROCESS
56 |
57 | END
58 | {
59 | Write-Output $output
60 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
61 | } #END
62 | }
63 |
64 | $path = Join-Path $PSScriptRoot '\Ep7 Runspaces'
65 | #$path = 'E:\JimM\Dropbox\Dropbox (Personal)\ScriptScratch\YouTube\Ep8 Runspaces Pt2\Ep8 Runspaces Pt2'
66 |
67 | $script:syncHash = [hashtable]::Synchronized(@{ })
68 |
69 | $script:syncHash = Get-ChildItem -Path $path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
70 |
71 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.TitlePage) | Out-Null
72 |
73 | $script:syncHash.titleButtonNext.add_Click({
74 |
75 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.MiddlePage)
76 | })
77 |
78 | $script:syncHash.middleButtonNext.add_Click({
79 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.FinishPage)
80 | })
81 |
82 | $script:syncHash.middleButtonBack.add_Click({
83 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.TitlePage)
84 | })
85 |
86 | $script:syncHash.FinishButtonBack.add_Click({
87 | $script:syncHash.WizardWindowFrame.NavigationService.Navigate($script:syncHash.MiddlePage)
88 | })
89 | #endregion
90 |
91 |
92 | $script:syncHash.titleButton.add_Click({
93 |
94 | $syncHash.sleepSecs = $syncHash.titleTextBox.text
95 |
96 | $runspace = [runspacefactory]::CreateRunspace()
97 | $powerShell = [powershell]::Create()
98 | $powerShell.runspace = $runspace
99 | $runspace.Open()
100 | $runspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
101 |
102 | [void]$PowerShell.AddScript({
103 |
104 |
105 | Start-Sleep -Seconds $syncHash.sleepSecs
106 | #$syncHash.titleTextBlock.Text = "$($syncHash.sleepSecs) second sleep finished"
107 | #Wait-Debugger
108 | #Measure-Command -Expression {
109 | $syncHash.titleTextBlock.Dispatcher.Invoke([action]{
110 | $syncHash.titleTextBlock.Text = "$($syncHash.sleepSecs) second sleep finished"
111 | })
112 | #}
113 | })
114 |
115 | $AsyncObject = $PowerShell.BeginInvoke()
116 |
117 | })
118 |
119 |
120 | $script:syncHash.Window.ShowDialog() | Out-Null
--------------------------------------------------------------------------------
/Ep8 Runspaces Pt2/DebugRunspacePt2.ps1:
--------------------------------------------------------------------------------
1 | #Find PoSH process with the correct 'window title'
2 | Get-PSHostProcessInfo | Where-Object {$_.MainWindowTitle -eq 'MainWindow'} | Enter-PSHostProcess
3 |
4 | #Enter the runspace which is waiting for a debugger
5 | Get-Runspace | Where-Object {$_.Debugger.InBreakpoint -eq $true} | Debug-Runspace
6 |
7 |
8 | Get-Runspace | Where-Object { $_.Id -ne 1 } | ForEach-Object { $_.closeasync() }
9 |
10 | Get-Runspace | Where-Object { $_.Id -ne 1 } | ForEach-Object { $_.dispose() }
--------------------------------------------------------------------------------
/Ep8 Runspaces Pt2/Ep8 Runspaces Pt2/Finish.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Ep8 Runspaces Pt2/Ep8 Runspaces Pt2/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Ep8 Runspaces Pt2/Ep8 Runspaces Pt2/Middle.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Ep8 Runspaces Pt2/Ep8 Runspaces Pt2/Title.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Ep8 Runspaces Pt2/Ep8 Runspaces1.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .NOTES
3 | ===========================================================================
4 | Created on: 2017/04/07
5 | Created by: Jim Moyle
6 | GitHub link: https://github.com/JimMoyle/GUIDemo
7 | Twitter: @JimMoyle
8 | ===========================================================================
9 | .DESCRIPTION
10 | A description of the file.
11 | #>
12 |
13 | function Get-XamlObject {
14 | [CmdletBinding()]
15 | param(
16 | [Parameter(Position = 0,
17 | Mandatory = $true,
18 | ValuefromPipelineByPropertyName = $true,
19 | ValuefromPipeline = $true)]
20 | [Alias("FullName")]
21 | [System.String[]]$Path
22 | )
23 |
24 | BEGIN
25 | {
26 | Set-StrictMode -Version Latest
27 | $expandedParams = $null
28 | $PSBoundParameters.GetEnumerator() | ForEach-Object { $expandedParams += ' -' + $_.key + ' '; $expandedParams += $_.value }
29 | Write-Verbose "Starting: $($MyInvocation.MyCommand.Name)$expandedParams"
30 | $output = @{ }
31 | Add-Type -AssemblyName presentationframework, presentationcore
32 | } #BEGIN
33 |
34 | PROCESS {
35 | try
36 | {
37 | foreach ($xamlFile in $Path)
38 | {
39 | #Wait-Debugger
40 | #Change content of Xaml file to be a set of powershell GUI objects
41 | $inputXML = Get-Content -Path $xamlFile -ErrorAction Stop
42 | [xml]$xaml = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace 'x:Class=".*?"', '' -replace 'd:DesignHeight="\d*?"', '' -replace 'd:DesignWidth="\d*?"', ''
43 | $tempform = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $xaml -ErrorAction Stop))
44 |
45 | #Grab named objects from tree and put in a flat structure using Xpath
46 | $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]")
47 | $namedNodes | ForEach-Object {
48 | $output.Add($_.Name, $tempform.FindName($_.Name))
49 | } #foreach-object
50 | } #foreach xamlpath
51 | } #try
52 | catch
53 | {
54 | throw $error[0]
55 | } #catch
56 | } #PROCESS
57 |
58 | END
59 | {
60 | Write-Output $output
61 | Write-Verbose "Finished: $($MyInvocation.Mycommand)"
62 | } #END
63 | }
64 |
65 | #Set Starting path and create Synchronised hash table to be read across multiple runspaces
66 | $script:syncHash = [hashtable]::Synchronized(@{ })
67 | $syncHash.path = Join-Path $PSScriptRoot '\Ep8 Runspaces Pt2'
68 |
69 | #Load function into Sessionstate object for injection into runspace
70 | $ssGetXamlObject = Get-Content Function:\Get-XamlObject -ErrorAction Stop
71 | $ssfeGetXamlObject = New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList 'Get-XamlObject', $ssGetXamlObject
72 |
73 | #Add Function to session state
74 | $InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
75 | $InitialSessionState.Commands.Add($ssfeGetXamlObject)
76 |
77 | $runspace = [runspacefactory]::CreateRunspace($InitialSessionState) #Add Session State to runspace at creation
78 | $powerShell = [powershell]::Create()
79 | $powerShell.runspace = $runspace
80 | $runspace.ThreadOptions = "ReuseThread" #Helps to prevent memory leaks, show runspace config in console
81 | $runspace.ApartmentState = "STA" #Needs to be in STA mode for WPF to work
82 | $runspace.Open()
83 | $runspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
84 |
85 | [void]$PowerShell.AddScript({
86 |
87 | $wpf = Get-ChildItem -Path $syncHash.path -Filter *.xaml -file | Where-Object { $_.Name -ne 'App.xaml' } | Get-XamlObject
88 | $wpf.GetEnumerator() | ForEach-Object {$script:SyncHash.add($_.name,$_.value)} #Add all WPF objects to synchash variable
89 |
90 | #Section Timer
91 | #We'll create a timer, this is for UI responsivness as Dispatcher.invoke is slow as a depressed slug!
92 |
93 | $updateBlock = {
94 | if ($syncHash.watchnumber -or $syncHash.titleResultTextBlock.Text -ne $syncHash.watchedNumber){
95 | $syncHash.titleResultTextBlock.Text = $syncHash.watchedNumber
96 | }
97 | $syncHash.titleTimerTextBlock.Text = $syncHash.finalTime
98 |
99 | #Section for runspace cleanup
100 | $syncHash.rs = Get-Runspace
101 | $syncHash.middleBusyTextBlock.text = $syncHash.rs | Where-Object {$_.RunspaceAvailability -eq 'Busy'} | Measure-Object | Select-Object -ExpandProperty Count
102 | $syncHash.middleAvailableTextBlock.text = $syncHash.rs | Where-Object {$_.RunspaceAvailability -eq 'Available'} | Measure-Object | Select-Object -ExpandProperty Count
103 | $syncHash.middleOpenTextBlock.text = $syncHash.rs | Where-Object {$_.RunspaceAvailability -eq 'Open'} | Measure-Object | Select-Object -ExpandProperty Count
104 | $syncHash.middleTotalTextBlock.text = $syncHash.rs | Measure-Object | Select-Object -ExpandProperty Count
105 | #Endsection
106 | }
107 |
108 | $timer = New-Object System.Windows.Threading.DispatcherTimer
109 | # Which will fire 100 times every second
110 | $timer.Interval = [TimeSpan]"0:0:0.01"
111 | # And will invoke the $updateBlock method
112 | $timer.Add_Tick($updateBlock)
113 | # Now start the timer running
114 | $timer.Start()
115 | if ($timer.IsEnabled)
116 | {
117 | Write-Output 'UI timer started'
118 | }
119 |
120 | #EndSection
121 |
122 | #Section Navigation buttons
123 | $syncHash.WizardWindowFrame.NavigationService.Navigate($syncHash.TitlePage) | Out-Null
124 | $syncHash.titleButtonNext.add_Click({
125 |
126 | $syncHash.WizardWindowFrame.NavigationService.Navigate($syncHash.MiddlePage)
127 | })
128 | $syncHash.middleButtonNext.add_Click({
129 | $syncHash.WizardWindowFrame.NavigationService.Navigate($syncHash.FinishPage)
130 | })
131 | $syncHash.middleButtonBack.add_Click({
132 | $syncHash.WizardWindowFrame.NavigationService.Navigate($syncHash.TitlePage)
133 | })
134 | $syncHash.FinishButtonBack.add_Click({
135 | $syncHash.WizardWindowFrame.NavigationService.Navigate($syncHash.MiddlePage)
136 | })
137 | #EndSection
138 |
139 | #Section Dispatcher vs Timer
140 |
141 | $syncHash.titleDispatcherButton.add_Click({
142 |
143 | $syncHash.iterations = $syncHash.titleTextBox.text
144 | $syncHash.titleDispatcherTextBlock.Text = ''
145 | $syncHash.titleResultTextBlock.Text = ''
146 |
147 | $runspace = [runspacefactory]::CreateRunspace()
148 | $powerShell = [powershell]::Create()
149 | $powerShell.runspace = $runspace
150 | $runspace.ThreadOptions = 'ReuseThread'
151 | $runspace.ApartmentState = 'STA'
152 | $runspace.Open()
153 | $runspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
154 |
155 | [void]$PowerShell.AddScript({
156 | $result = Measure-Command { # Using measure command to see how long entire process takes
157 | 1..$syncHash.iterations | ForEach-Object {
158 | $syncHash.titleResultTextBlock.Dispatcher.Invoke([action]{
159 | $syncHash.titleResultTextBlock.Text = "$_" #For each number we update the UI via dispatcher
160 | })
161 | }
162 | }
163 | $syncHash.watchednumber = $syncHash.iterations #ignore as it stops race conditions between timer and dispatcher method
164 | $syncHash.titleDispatcherTextBlock.Dispatcher.Invoke([action]{
165 | $syncHash.titleDispatcherTextBlock.Text = "$("{0:N0}" -f $result.TotalMilliseconds) ms" #update UI with total time taken
166 | })
167 | })
168 |
169 | #start runspace and save details about runspace for later use
170 | $syncHash.Powershell = $PowerShell
171 | $syncHash.AsyncObject = $PowerShell.BeginInvoke()
172 |
173 | })
174 |
175 | $syncHash.titleTimerButton.add_Click({
176 |
177 | $syncHash.iterations = $syncHash.titleTextBox.text
178 | $syncHash.titleTimerTextBlock.Text = ''
179 | $syncHash.finalTime = ''
180 |
181 | $runspace = [runspacefactory]::CreateRunspace()
182 | $powerShell = [powershell]::Create()
183 | $powerShell.runspace = $runspace
184 | $runspace.ThreadOptions = 'ReuseThread'
185 | $runspace.ApartmentState = 'STA'
186 | $runspace.Open()
187 | $runspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
188 |
189 | [void]$PowerShell.AddScript({
190 | $syncHash.watchnumber = $true #Tell if statement in timer to run code
191 |
192 | $result = Measure-Command {
193 | 1..$syncHash.iterations | ForEach-Object {
194 | $syncHash.watchedNumber = "$_" #Not updating thread here, just updating variable.
195 | }
196 | }
197 |
198 | $syncHash.finalTime = "$("{0:N0}" -f $result.TotalMilliseconds) ms" #Format time and again update variable, not UI
199 | $syncHash.watchnumber = $false
200 | })
201 |
202 | #this time we are not saving runspace config for later use, just starting it
203 | $AsyncObject = $PowerShell.BeginInvoke()
204 |
205 | })
206 | #EndSection
207 |
208 | #Section Runspace Cleanup
209 | $syncHash.middleResetButton.add_Click({
210 | Get-Runspace | Where-Object {$_.RunspaceAvailability -eq 'Available'} | ForEach-Object {$_.dispose()}
211 | })
212 |
213 | $syncHash.middleReset3Button.add_Click({
214 | #Wait-Debugger
215 | If ($syncHash.AsyncObject.isCompleted)
216 | {
217 | [void]$syncHash.Powershell.EndInvoke($syncHash.AsyncObject)
218 | $syncHash.Powershell.runspace.close()
219 | $syncHash.Powershell.runspace.dispose()
220 | }
221 | })
222 | #EndSection
223 |
224 | $script:syncHash.Window.ShowDialog() | Out-Null
225 | })
226 |
227 | $AsyncObject = $PowerShell.BeginInvoke()
228 |
229 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GUIDemo
2 |
3 | Code snippets to go along with the You Tube series 'WPF and PowerShell'
4 |
5 | https://www.youtube.com/playlist?list=PLsg-xXEEmCJozYQCiBxO5ydYI1KIV2pI4
6 |
--------------------------------------------------------------------------------
/bubbleuproutedevents.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JimMoyle/GUIDemo/fc95489a9fbc3e7c6fecb6610e150cb1621787af/bubbleuproutedevents.xml
--------------------------------------------------------------------------------