2017-06-05 53 views
0

我是WPF和使用PowerShell進行事件處理的新手,我想實現的是點擊一個按鈕,進度條應該顯示在0-100之間。但是,當我運行以下代碼段時,它會計算add_click塊內的整個代碼,並且它僅顯示循環中的最後一次迭代。 我知道也許這是一個愚蠢的解決方案,但我確實需要一些幫助。

$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() 

$工具1是一個標籤。 $ tool1_pb是一個進度條。 $ consoleOutput是一個 文本框。

+3

你的代碼的功能禮貌,更新,這意味着當你的循環執行的UI不能更新UI中的同一個線程上運行。 – mm8

+0

是的,我知道必須有某種線程問題,你能否爲我提供解決方案來解決這個問題。謝謝您的好意。 :) –

+0

您需要使用'BeginInvoke()'創建一個新的運行空間。當我試圖和你一樣做同樣的事時,這幫助了我。 https://learn-powershell.net/2012/10/14/powershell-and-wpf-writing-data-to-a-ui-from-a-different-runspace/ – Nick

回答

0

我整合了WPF和PowerShell。 This網站幫了我很大的忙。你不能更新是相同的線程上運行的UI,所以你需要調用使用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() 

然後更新什麼是你需要的,你可以使用一個新的運行空間Window.Dispatcher.Invoke

$Global:uiHash.Window.Dispatcher.Invoke([action]{$Global:uiHash.Window.Title = "MyWindowTitle"},"Normal") 

編輯

$Global:uiHash.Button1.Add_Click(tool1_progress) 

編輯

扔在你XML,這將工作。您必須在另一個之上創建另一個運行空間,以便不斷更新文本框和進度欄。請注意,synchash務必是$Global:synchash。的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 
+0

感謝尼克,我實際上是通過你建議的網站,將嘗試實施的變化,並看看如何使它的工作:) –

+0

真棒,如果你遇到任何問題,讓我知道。 WPF和PS可能是一場噩夢,讓我們一起合作吧! – Nick

+0

嗨,尼克, 進入另一個問題,爲了改變用戶界面中的東西,我們使用的是「uiHash.Window.Dispatcher.Invoke」,但是我應該在哪裏放置$ uiHash.button.add_click事件?我試着把這個腳本放在一起,仍然遇到同樣的問題,因爲它又是同一個線程的一部分。我應該做些什麼 ?請幫助。 –