2016-03-07 73 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和基于表单的脚本提供了一个后台工作器。