Flash info

"Those who forget to script are doomed to repeat their work."

Jeffery Hicks (PowerShell MVP)

 
Accueil arrow Forum

Bienvenue sur le forum PowerShell-Scripting.com

 
marcci
Utilisateur

PowerShelleur Amateur
Messages: 90
graphgraph
Karma: 10  
Runspace et click event - 28/07/17 13:39 Bonjour à tous,

voila un petit bout de code:
Code:

  Add-Type -AssemblyName PresentationFrameworkPresentationCoreWindowsBase [xml]$Main =@' <Window      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"     Title="MainWindow" Height="154" Width="270">     <Grid>         <Button Name="button" Content="Button" HorizontalAlignment="Left" Margin="88,60,0,0"  VerticalAlignment="Top" Width="75"/>         <TextBox Name="txtBox" Text="{Binding Col1}" HorizontalAlignment="Left" Height="23" Margin=" 62,5,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>         <TextBox Name="txtBox2" HorizontalAlignment="Left" IsEnabled="False" Height="23" Margin=" 62,30,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>     </Grid> </Window> '@ $reader = New-Object System.Xml.XmlNodeReader $Main $MainForm = [Windows.Markup.XamlReader]::Load($reader) #---- Initialise GUI Object ----- $Main.SelectNodes("//*[@Name]") | ForEach-Object Set-Variable -Name ($_.Name) -Value $MainForm.FindName($_.Name) } #Initialisation d'une DataTable pour l'exemple $DataTable = New-Object System.Data.DataTable [void]$DataTable.Columns.Add('Col1') $DataTable.Rows.Add('Coucou') $MainForm.DataContext $DataTable [System.Windows.RoutedEventHandler]$ClickEvent =  {     [scriptblock]$script =      {         param         (             [System.Data.DataTable]$scriptdata         )         #Pour être sur le script fait quelque chose dans le runspace         $scriptdata.Rows[0].Col1 'Hello'     }     [scriptblock]$action =      {         if($Sender.RunspaceAvailability -eq 'Available')         {             #Je passe la txtbox2 à IsEnable             $txtbox2.IsEnabled $true             Write-Host 'fini'             $Sender.Close()         }     }     $RunspaceFactory = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()     $Powershell=[System.Management.Automation.PowerShell]::Create()          #Je rajoute mon script avec les arguments associé     [void]$Powershell.AddScript($script).AddArgument($DataTable)     $Powershell.Runspace $RunspaceFactory     $RunspaceFactory.Open()          # Je passe le txtbox2 au runspace     $RunspaceFactory.SessionStateProxy.SetVariable("txtbox2",$txtBox2)          # Je créer un evenement pour checker le déroulement du runspace     Register-ObjectEvent -InputObject $RunspaceFactory -EventName 'AvailabilityChanged' -Action $action          # Je démarre mon runspace     $Powershell.BeginInvoke() } $button.add_Click($ClickEvent) $MainForm.ShowDialog()



Je clique sur le bouton, des actions sont mené.
Une fois que le runspace devient dispo il doit exécuter d'autres actions.

Le problème et qu'il ne les exécute pas lors du premier clique. Il le fait lors d'un second clique sur le bouton.

Une âme charitable pour me dire ce que j'ai mal fait s'il vous plait...
Merci.
  | | L'administrateur a désactivé l'accés public en écriture.
6ratgus
Utilisateur

PowerShelleur Platinum
Messages: 1658
graphgraph
Karma: 121  
Re:Runspace et click event - 31/07/17 15:32 salut macci

je n'y connaît rien en runspace mais il me semble que l'initialisation du runspace ce place en dehors d'un event un tuto ici

plus un exemple
  | | L'administrateur a désactivé l'accés public en écriture.
Laurent Dardenne
Utilisateur

PowerShelleur Platinum
Messages: 5724
graph
Karma: 209  
Re:Runspace et click event - 31/07/17 20:22 Avec ces traces on comprend un peu mieux ce qui se passe :
Code:

  [System.Windows.RoutedEventHandler]$ClickEvent =  {     Write-Warning "ClickEvent"     Write-Warning "$(Get-EventSubscriber |out-string)"          [scriptblock]$script =      {         param         (             [System.Data.DataTable]$scriptdata         )         #Pour être sur le script fait quelque chose dans le runspace         $scriptdata.Rows[0].Col1 'Hello'     }     [scriptblock]$action =      {         Write-Warning "Action Event"         Write-Warning "$($EventSubscriber |out-string)"         if($Sender.RunspaceAvailability -eq 'Available')         {             #Je passe la txtbox2 à IsEnable             $txtbox2.IsEnabled $true             Write-Host 'fini'             $Sender.Close()         }     }     $RunspaceFactory = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()     $Powershell=[System.Management.Automation.PowerShell]::Create()          #Je rajoute mon script avec les arguments associé     [void]$Powershell.AddScript($script).AddArgument($DataTable)     $Powershell.Runspace $RunspaceFactory     $RunspaceFactory.Open()          # Je passe le txtbox2 au runspace     $RunspaceFactory.SessionStateProxy.SetVariable("txtbox2",$txtBox2)          # Je créer un evenement pour checker le déroulement du runspace     Register-ObjectEvent -InputObject $RunspaceFactory -EventName 'AvailabilityChanged' -Action $action          Write-Warning "Je démarre mon runspace"     $Powershell.BeginInvoke() }


Le premier appel fonctionne, mais le gestionnaire d'event Powershell ($Action) est quel part où n'est pas le thread du GUI lorsque le code de $ClickEvent est terminé.

Lorsqu'on clique une seconde fois, le gestionnaire d'event de PS ($action) se déclenche, puis c'est le code de $ClickEvent qui s'exécute.
Quelqu'un 'bloque' qq chose

Ensuite on constate que la 'queue' d'event de PS ($action) contient un event supplémentaire à chaque fois que l'on clique sur le bouton.

De plus il me semble que des appels à dispose ou close manquent...

Je ne suis pas allé plus loin pour te fournir une explication plus détaillée
Mais je suis curieux de connaitre le pourquoi du comment
Tutoriels PowerShell
  | | L'administrateur a désactivé l'accés public en écriture.
marcci
Utilisateur

PowerShelleur Amateur
Messages: 90
graphgraph
Karma: 10  
Re:Runspace et click event - 2/08/17 12:44 Salut à tous,
alors...

Merci 6ratgus pour les lien, car c'est bien là qu'était la solution.

Pour faire marcher mon code, il faut que l'UI soit instancié dans un runspace défini et que le click_event lance ses actions dans un autre runspace.
Et la tout marche au premier clique.

Ce que je retient, c'est qu'il doit y des restrictions sur le runspace qui contient l'instance principale de powershell, ce n'est qu'un sentiment et je n'ai pas le courage ni les compétences pour fouiller
et qu'il faut faire attention avec les runspace, powershell plante violement si on fait une cagade .

Le petit bout de code pour ceux que ça intéresse.
Ce n'est qu'un brouillon...
Code:

  Add-Type -AssemblyName PresentationFrameworkPresentationCoreWindowsBase $syncHash = [hashtable]::Synchronized(@{}) #<---- Object conteneur /!\ #Pincipal runspace $newRunspace =[runspacefactory]::CreateRunspace() $newRunspace.ApartmentState "STA" $newRunspace.ThreadOptions "ReuseThread"          $newRunspace.Open() $newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)           $psCmd = [PowerShell]::Create().AddScript({ #<----- UI construction [xml]$Main =@' <Window      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"     Title="MainWindow" Height="154" Width="270">     <Grid>         <Button Name="button" Content="Button" HorizontalAlignment="Left" Margin="88,60,0,0"  VerticalAlignment="Top" Width="75"/>         <TextBox Name="txtBox" Text="{Binding Col1}" HorizontalAlignment="Left" Height="23" Margin=" 62,5,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>         <TextBox Name="txtBox2" HorizontalAlignment="Left" IsEnabled="false" Height="23" Margin=" 62,30,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>     </Grid> </Window> '@ $reader = New-Object System.Xml.XmlNodeReader $Main #<----- fill Object conteneur $syncHash.MainForm = [Windows.Markup.XamlReader]::Load($reader) $syncHash.txtBox $syncHash.MainForm.FindName("txtBox") $syncHash.txtBox2 $syncHash.MainForm.FindName("txtBox2") $syncHash.Button $syncHash.MainForm.FindName("button") $syncHash.Error $Error $syncHash.Data = New-Object System.Data.DataTable [void]$syncHash.Data.Columns.Add('Col1') [void]$syncHash.Data.Rows.Add('Coucou') $syncHash.MainForm.DataContext $syncHash.Data #<---- ClickEvent definition [System.Windows.RoutedEventHandler]$ClickEvent =  {     Add-Content -Value 'Click Event' -Path C:\temp\log.txt #<----- Click action     [scriptblock]$script =      {             #Pour être sur le script fait quelque chose dans le runspace             Add-Content -Value 'Déroulement du click' -path c:\temp\log.txt             $hash.Data.Rows[0].Col1 'Hello'             $hash.txtBox2.Dispatcher.invoke([action]{$hash.txtBox2.IsEnabled=$true},"Normal")     } #<---- Runspace Availability change action         [scriptblock]$action =      {         if($Sender.RunspaceAvailability -eq 'Available')         {             Add-Content "$(Get-EventSubscriber |out-string)" -path c:\temp\log.txt             $Sender.Close()             Add-Content -Value 'Action Closed' -path c:\temp\log.txt         }     }      #<---- Click runspace definition     $RunspaceFactory = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()     $RunspaceFactory.ApartmentState "MTA"     $RunspaceFactory.Open()     $RunspaceFactory.SessionStateProxy.SetVariable("hash",$syncHash)     Register-ObjectEvent -InputObject $RunspaceFactory -EventName 'AvailabilityChanged' -Action $action -MessageData $hash     $Powershell=[System.Management.Automation.PowerShell]::Create()     [void]$Powershell.AddScript($script)     $Powershell.Runspace $RunspaceFactory     Add-Content "Je démarre mon runspace" -path c:\temp\log.txt     $Powershell.BeginInvoke() |Out-Null } #<--- Add click $syncHash.Button.Add_Click($ClickEvent) $syncHash.MainForm.ShowDialog() |Out-Null }) $psCmd.Runspace $newRunspace $Gui $psCmd.BeginInvoke()




Tant que je suis dans les runspace...
Savez vous comment faire pour voir ce qu'il se passe à l'intérieur ?
Les fichiers de logs, ce n'est pas pratique.

Message édité par: marcci, à: 2/08/17 13:46
  | | L'administrateur a désactivé l'accés public en écriture.
Laurent Dardenne
Utilisateur

PowerShelleur Platinum
Messages: 5724
graph
Karma: 209  
Re:Runspace et click event - 2/08/17 19:35 marcci écrit:

Les fichiers de logs, ce n'est pas pratique.

Avec Log4Posh tu peux avoir un appender Console, les traces de debug sont affichées dans la console.
Ainsi on peut par exemple débugger une règle PSScriptAnalyzer codée avec PS ou afficher les traces d'un job (runspace inside)
Tutoriels PowerShell
  | | L'administrateur a désactivé l'accés public en écriture.
© 2020 PowerShell-Scripting.com