2016-03-07 54 views
1

WPF運行空間崩潰我正在寫一個PowerShell腳本,這installes各種驅動程序。使用PowerShell版本2

我的腳本工作正常,所以我要添加使用WPF的GUI。 首先,我使用WPF創建了一個gui,沒有什麼特別的,只是一個帶有標籤的窗口。

我想更新從我的安裝腳本此標籤。所以我創建了兩個運行空間,一個創建並顯示WPF gui,另一個執行我的安裝腳本。 只要我使用的是PowerShell版本3或更高版本,就可以正常工作。對於必須使用新的Windows 7安裝的powershell 2,wpf運行空間會崩潰。

我希望有一種方式來獲得這種使用PowerShell版本2

下面是一個示例腳本工作,demonstating我在做什麼。

######################################################################################### 
# 
# W P F - R U N S P A C E 
# 
######################################################################################### 
$syncHashWpfLuaNotification = [hashtable]::Synchronized(@{}) 
$runspaceWpfLuaNotification =[runspacefactory]::CreateRunspace() 
$runspaceWpfLuaNotification.ApartmentState = "STA" 
$runspaceWpfLuaNotification.ThreadOptions = "ReuseThread"   
$runspaceWpfLuaNotification.Open() 
$runspaceWpfLuaNotification.SessionStateProxy.SetVariable("syncHashWpfLuaNotification",$syncHashWpfLuaNotification)   
$psCmd = [PowerShell]::Create().AddScript({ 
    [void][System.Reflection.Assembly]::LoadWithPartialName('presentationframework') 
    [xml]$xaml = @" 
<Window 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="TreiberInstaller" Height="431" Width="626" Background="Black" 
     WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen"> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="1*" /> 
      <ColumnDefinition Width="2*" /> 
      <ColumnDefinition Width="1*" /> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="2*" /> 
      <RowDefinition Height="1*" /> 
      <RowDefinition Height="1*" /> 
     </Grid.RowDefinitions> 

     <Label Name="lblProgress" Content="Progress" HorizontalAlignment="Center" Grid.Column="1" Grid.Row="2" VerticalAlignment="Top" Foreground="White" FontFamily="Calibri" FontSize="18" HorizontalContentAlignment="Center"/> 

    </Grid> 
</Window> 
"@ 
    $reader=(New-Object System.Xml.XmlNodeReader $xaml) 
    $syncHashWpfLuaNotification.Window = [Windows.Markup.XamlReader]::Load($reader) 
    $syncHashWpfLuaNotification.lblProgress = $syncHashWpfLuaNotification.window.FindName("lblProgress") 
    $syncHashWpfLuaNotification.Window.ShowDialog() | Out-Null 
    $syncHashWpfLuaNotification.Error = $Error 
}) 
$psCmd.Runspace = $runspaceWpfLuaNotification 
$data = $psCmd.BeginInvoke() 
Sleep -Milliseconds 450 # Wait a moment that the gui is ready 




######################################################################################### 
# 
# W O R K E R - R U N S P A C E 
# 
######################################################################################### 
$ScriptBlock = { 
    #---------------------------------------------------------------------- 
    # SetLabelText: Sets the lable-text 
    #---------------------------------------------------------------------- 
    function SetLabelText 
    { 
     param(
       [Parameter(Position=0, Mandatory = $true, ValueFromPipeline = $false)] 
       [ValidateNotNullOrEmpty()] 
       [string]$Text 
      ) 

     if(-not $syncHashWpfLuaNotification) {return} 

     try 
     { 
      $syncHashWpfLuaNotification.Window.Dispatcher.invoke(
        [action]{$syncHashWpfLuaNotification.lblProgress.Content = $Text}, 
        "Normal" 
      ) 
     } 
     catch {} 
    } 

    #---------------------------------------------------------------------- 
    # CloseProgressWindow: Closes the window 
    #---------------------------------------------------------------------- 
    function CloseProgressWindow() 
    { 
     if(-not $syncHashWpfLuaNotification) {return} 

     try 
     { 
      $syncHashWpfLuaNotification.Window.Dispatcher.invoke(
        [action]{$syncHashWpfLuaNotification.Window.Close()}, 
        "Normal" 
      ) 
     } 
     catch{} 
    } 



    #Starting here 
    SetLabelText -Text "Starting installation..." 

    Sleep 2 

    for($i=1;$i -le 19; $i++) 
    { 
     SetLabelText -Text ("Progress Step " + $i) 
    } 

    for($i=20;$i -le 24; $i++) 
    { 
     SetLabelText -Text ("Progress Step " + $i) 
     Sleep 1 
    } 

    CloseProgressWindow 
} #End of $ScriptBlock 


$syncHash1 = [hashtable]::Synchronized(@{}) 
$workerRunspace =[runspacefactory]::CreateRunspace() 
$workerRunspace.ApartmentState = "STA" 
$workerRunspace.ThreadOptions = "ReuseThread"   
$workerRunspace.Open() 
$workerRunspace.SessionStateProxy.SetVariable("syncHash1",$syncHash1)   
$workerRunspace.SessionStateProxy.SetVariable("syncHashWpfLuaNotification",$syncHashWpfLuaNotification)   
$psCmd1 = [PowerShell]::Create().AddScript($ScriptBlock) 
$psCmd1.Runspace = $workerRunspace 
$data = $psCmd1.BeginInvoke() 






######################################################################################### 
# 
# S C R I P T E N D 
# 
######################################################################################### 

#Wait for end of both runspaces 
while(($runspaceWpfLuaNotification.RunspaceAvailability -eq "Busy") -or ($workerRunspace.RunspaceAvailability -eq "Busy")) 
{ 
    if($runspaceWpfLuaNotification.RunspaceAvailability -eq "Busy") { Write-Host "Window is open" } 
    if($workerRunspace.RunspaceAvailability -eq "Busy") { Write-Host "Worker is running" } 

    Sleep 1 
} 

Write-Host "Script ended" 
+1

'[action] {$ syncHashWpfLuaNotification.lblProgress.Content = $ Text},「Normal」 - >'「Normal」,[action [object]] [scriptblock] :: create({$ syncHashWpfLuaNotification.lblProgress.Content = $ args [0]}),$ Text'; '[動作] {$ syncHashWpfLuaNotification.Window.Close()}, 「正常」' - >' 「正常」,[動作] [腳本塊] ::創建({$ syncHashWpfLuaNotification.Window.Close()})'。 – PetSerAl

+0

是的,就是這樣!這適用於PowerShell 2.0。非常感謝。你可以發表這個答案,所以我可以將其標記爲正確答案。 – CrazyMetal

回答

1

有一些問題,你如何通過委託給Dispatcher.Invoke通話。

  • ScriptBlock文字限定爲當前會話狀態。如果你傳遞界ScriptBlock不同Runspace,那麼它可能會導致一些不希望的效果,如代碼目標Runspace或死鎖不被調用。關於這個請看my other answer。所以,你需要做的第一件事是創建新的不受限制的ScriptBlock。你可以用[ScriptBlock]::Create的方法做到這一點。
  • 由於ScriptBlock不再一定到當前會話狀態,你不能從它指變量,就像你在你的代碼$Text做。您應該將它們作爲附加參數傳遞給Dispatcher.Invoke
  • 在.NET Framework 3.5中,它將與PowerShell v2一起使用,因此在Dispatcher類中沒有Invoke(Action, DispatcherPriority)過載,因此Invoke([Action]{...}, "Normal")將被解析爲此Invoke(Delegate, Object[])方法。您應該使用不同的重載:Invoke(DispatcherPriority, Delegate),它存在於.NET Framework 3.5中。
0

嘗試下載WPFRunspace,應該與PS V2一起使用。它爲WPF和基於表單的腳本提供了一個後臺工作器。

相關問題