Как подключиться из среды выполнения Powershell обратно к основному потоку Powershell? - PullRequest
0 голосов
/ 12 марта 2019

Я начал размышлять о пространствах выполнения в powershell, и я смог сделать следующее

  • Создать RunSpace
  • Передать переменные
  • Passпредустановленная функция
  • GUI / WPF появляется, и я даже могу манипулировать элементами на нем (например, изменение текста в текстовом блоке)

Проблема заключается вкнопки (BTN_Exit) ... Я хотел бы добиться этого при нажатии, это не только закрывает графический интерфейс, но закрывает RunSpace, где он запускается.Я дошел до того, что мне удалось закрыть графический интерфейс и даже вызвать последовательность закрытия для Runspace, но (я предполагаю), поскольку вызываемая функция выполняется в самом RunSpace, она просто зависает (RunSpace остается в «закрытии»)состояние) - по-видимому, Powershell не может убить себя :) К счастью, я все еще могу удалить его из основного потока с помощью $(Get-Runspace)[-1].Dispose() (Вручную)

Я считаю, что мне нужно подключиться к основному потоку, гдеGUI Runspace был создан и закройте его оттуда, но я не могу вернуться туда в функции.Вручную, если окно открыто, я могу выполнить все командлеты в функции close-runspace, и она достигает желаемой цели.

Я попытался добавить $rs.connect($(Get-Runspace).Name -eq "Runspace1") & $RS.disconnect() Если я попробую то же самое на«Ручка» или Экземпляр дает тот же результат.Также я не смог вызвать оригинальную функцию по нажатию кнопки, не передав функцию в RunSpace.

Как мне программно добраться до такой степени, что при нажатии кнопки она закрывает графический интерфейс и удаляет пространство выполнения?

Вот код:

#===[___VARIABLES___]===
$GUI = [hashtable]::Synchronized(@{})
$GUI.Host = $host

#===[___FUNCTIONS___]===
function Close-RunSpace {
  if(!($RSI01H.Iscompleted)){
    $GUI.BS.Dispatcher.invoke([action]{
      $GUI.BS.Close()
    })
  }
  $RSI01.EndInvoke($RSI01H)
  $RS.Close()
  $RS.Dispose()
}

#===[__RunSpaceCfg__]===
$RS_ISS = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$RS_ISS.Commands.Add((New-Object System.Management.Automation.Runspaces.SessionStateFunctionEntry -ArgumentList 'Close-RunSpace', (Get-Content Function:\Close-RunSpace -ErrorAction Stop)))
$RS = [runspacefactory]::CreateRunspace($RS_ISS)
$RS.ApartmentState = "STA"
$RS.ThreadOptions = "ReuseThread"
$RS.Open()
$RS.SessionStateProxy.SetVariable("GUI",$GUI)
$RS.SessionStateProxy.SetVariable("RS",$RS)
$RS.SessionStateProxy.SetVariable("RSI01",$RSI01)
$RS.SessionStateProxy.SetVariable("RSI01H",$RSI01H)

#===[___EXECUTION___]===
$RSI01 = [powershell]::Create().AddScript(
  {
    [void][System.Reflection.Assembly]::LoadWithPartialName("PresentationCore")
    [void][System.Reflection.Assembly]::LoadWithPartialName("PresentationFramework")
    [void][System.Reflection.Assembly]::LoadWithPartialName("WindowsBase")
    [void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

    $Def_XAML = DATA {'
      <Window x:Name="BS" x:Class="PST.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:PST"
        mc:Ignorable="d"
        Title="BootStrapR" 
        Height="450" 
        Width="800" 
        ResizeMode="NoResize" 
        Topmost="True" 
        FontFamily="Arial" 
        WindowStartupLocation="CenterScreen" 
        WindowStyle="None">
      <Grid>
        <Button x:Name="BTN_Update" 
          Content="Update" 
          HorizontalAlignment="Left" 
          VerticalAlignment="Top" 
          Margin="109,352,0,0" 
          Width="75"/>
        <Button x:Name="BTN_Exit" 
          Content="exit" 
          HorizontalAlignment="Left" 
          Margin="431,352,0,0" 
          VerticalAlignment="Top" 
          Width="75"/>
        <ProgressBar x:Name="pb" 
          HorizontalAlignment="Left" 
          Height="29" 
          Margin="10,150,0,0" 
          VerticalAlignment="Top" 
          Width="780" 
          Background="White" 
          Foreground="Black" 
          BorderBrush="White" 
          Value="0" />
        <TextBlock x:Name="pstext" 
          HorizontalAlignment="Left" 
          Height="266" 
          Margin="26,22,0,0" 
          TextWrapping="Wrap" 
          Text="TextBlock" 
          VerticalAlignment="Top" 
          Width="223"/>
        </Grid>
      </Window>
    '}

    [xml]$XAML = $Def_XAML -replace 'x:Class=*.*','' `
                           -replace 'mc:Ignorable="d"','' `
                           -replace "x:Name",'Name'
    $WPF = [Windows.Markup.XamlReader]::Load((New-Object System.Xml.XmlNodeReader $XAML))
    $XAML.SelectNodes("//*[@Name]") | ForEach-Object{
      $GUI."$($_.Name)" = $WPF.FindName($_.Name)
    }

    $GUI.Error = $Error

    $GUI.BTN_Exit.Add_Click({
      #$GUI.BS.Close()
      Close-RunSpace
    })

    $GUI.BTN_Update.Add_Click({
      $GUI.pb.Value+=1
    })

    $GUI.BS.ShowDialog() | Out-Null
  }
)
$RSI01.Runspace = $RS
$RSI01.Runspace.Name = "GUI"
$RSI01H = $RSI01.BeginInvoke()
...