2017-06-05 122 views
0

私はWPFとイベントハンドリングの初心者です。達成したいのは、ボタンをクリックするだけです。プログレスバーは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() 

$ TOOL1ラベルです。 $ 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") 

EDITあなたの中

$Global:uiHash.Button1.Add_Click(tool1_progress) 

EDIT

投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

こんにちはNick、 別の問題として、私たちが使っているUIのものを変更するために "uiHash.Window.Dispatcher.Invoke"がありますが、$ uiHash.button.add_clickイベントはどこに置かれますか?私はこのスクリプトと一緒に配置しようとしましたが、それは同じスレッドの一部であるため同じ問題に実行されています。私はどうしたらいいですか ?助けてください。 –

関連する問題