I am new to WPF and event-handling using powershell, what I want to achieve is on click of a button, the progress bar should be shown from 0-100. But when I am running the following piece of code, it computes the whole code inside the add_click block and it only shows the last iteration in the loop. I know maybe it is a silly solution, but I do need some help in this.
$syncHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$psCmd = [PowerShell]::Create().AddScript({
$XamlPath="C:\Forms\MyFormsv1.xaml"
$inputXML = Get-Content -Path $XamlPath
[xml]$Global:xmlWPF = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace '^<Win.*', '<Window'
#Add WPF and Windows Forms assemblies
try{
Add-Type -AssemblyName PresentationCore,PresentationFramework,WindowsBase,system.windows.forms
} catch {
Throw “Failed to load Windows Presentation Framework assemblies.”
}
$syncHash.Window=[Windows.Markup.XamlReader]::Load((new-object System.Xml.XmlNodeReader $xmlWPF))
[xml]$XAML = $xmlWPF
$xmlWPF.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | %{
$Global:synchash.Add($_.Name,$synchash.Window.FindName($_.Name) )}
function tool1_progress{
$var1=50
for($index=1 ; $index -le $var1; $index++)
{
[int]$tmpProgNum= ($index/$var1) * 100
$syncHash.tool1_pb.Value= $tmpProgNum
$syncHash.consoleOutput.Text=$index
Start-Sleep -Milliseconds 250
}
}
$syncHash.myButton.add_click({tool1_progress})
$syncHash.Window.ShowDialog() | out-null
})
$psCmd.Runspace = $newRunspace
$data = $psCmd.BeginInvoke()
$tool1 is a label. $tool1_pb is a progress bar. $consoleOutput is a text box.
I integrate WPF and PowerShell all the time. This website helped me immensely. You can't update a UI that's running on the same thread, so you need to invoke a new runspace using BeginInvoke()
$psCmd = [PowerShell]::Create().AddScript({
$Global:uiHash.Error = $Error
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase
$xaml = @"YOURXAMLHERE"
$Global:uiHash.Window=[Windows.Markup.XamlReader]::Parse($xaml )
[xml]$XAML = $xaml
$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | %{
$Global:uihash.Add($_.Name,$uihash.Window.FindName($_.Name) )}
$Global:uiHash.Window.ShowDialog() | out-null
})
$psCmd.Runspace = $newRunspace
$handle = $psCmd.BeginInvoke()
Then to update whatever it is you need, you would use Window.Dispatcher.Invoke
$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.Window.Title = "MyWindowTitle"},"Normal")
EDIT
$Global:uiHash.Button1.Add_Click(tool1_progress)
EDIT
Throw in your XML and this will work. You have to create another runspace on top of the other in order to keep updating the textbox and progress bar. Note that synchash
MUST be $Global:synchash
. Functions courtesy of this post.
$Global:syncHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
$psCmd = [PowerShell]::Create().AddScript({
$XamlPath="C:\Forms\MyFormsv1.xaml"
$inputXML = @"YOURXMLHERE"@
[xml]$Global:xmlWPF = $inputXML
#Add WPF and Windows Forms assemblies
try{
Add-Type -AssemblyName PresentationCore,PresentationFramework,WindowsBase,system.windows.forms
} catch {
Throw “Failed to load Windows Presentation Framework assemblies.”
}
$Global:syncHash.Window=[Windows.Markup.XamlReader]::Load((new-object System.Xml.XmlNodeReader $xmlWPF))
[xml]$XAML = $xmlWPF
$xmlWPF.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | %{
$Global:synchash.Add($_.Name,$Global:syncHash.Window.FindName($_.Name) )}
function Start-Runspace{
param($scriptblock)
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("SyncHash",$global:synchash)
$psCmd = [PowerShell]::Create().AddScript($ScriptBlock)
$psCmd.Runspace = $newRunspace
$psCMD.BeginInvoke()
}
$SB = {
$var1=50
for($index=1 ; $index -le $var1; $index++)
{
[int]$tmpProgNum= ($index/$var1) * 100
$Global:syncHash.Window.Dispatcher.Invoke([action]{$Global:Synchash.tool1_pb.value = "$tmpprognum"},"Normal")
$Global:syncHash.Window.Dispatcher.Invoke([action]{$Global:Synchash.consoleoutput.text = "$index"},"Normal")
Start-Sleep -Milliseconds 250
}
}
$Global:syncHash.myButton.add_click({Start-Runspace $SB})
$Global:syncHash.Window.ShowDialog() | out-null
})
$psCmd.Runspace = $newRunspace
$data = $psCmd.BeginInvoke()
start-sleep -Milliseconds 300
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.