2016-03-07 1 views
1

Я пишу сценарий powershell, который устанавливает различные драйверы.Сбой WPF с использованием powershell версии 2

Мой скрипт работает нормально, поэтому я хочу добавить gui с помощью WPF. Сначала я создал gui, используя WPF, ничего захватывающего, просто окно с меткой.

Я хочу обновить этот ярлык из моего установочного скрипта. Поэтому я создаю два пробела: один, который создает и показывает GUI WPF, а другой выполняет мой скрипт установки. Это работает отлично, пока я использую версию powershell версии 3 или выше. С powershell 2, которую я должен был использовать с новой установкой Windows 7, рабочая область 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'; '[action] {$ syncHashWpfLuaNotification.Window.Close()}," Normal "' -> '" Normal ", [action] [scriptblock] :: create ({$ 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, нет Invoke(Action, DispatcherPriority) перегрузки в Dispatcher классе, так что, Invoke([Action]{...}, "Normal") будут решены к этому методу Invoke(Delegate, Object[]) вместо этого. Вы должны использовать различную перегрузку: Invoke(DispatcherPriority, Delegate), которая существует в .NET Framework 3.5.
0

Попробуйте загрузить WPFRunspace, который должен работать с PS V2. Он предоставляет фонового рабочего для сценариев WPF и Forms.