Когда в Powershell используется GUI
(например, созданный с помощью PrimalForms),
при вызове длительных функций интерфейс формы не радует своей отзывчивостью. Если
вы работаете с C#, то
можно выполнить эту длительную функцию в отдельном потоке и использовать синхронизированную
переменную для передачи данных между потоками. В Powershell возможно сделать тоже самое.
Используем функцию [HashTable]::Synchronized()
для получения синхронизированной переменной, которая будет использоваться
потоками:
$MyShared = [HashTable]::Synchronized(@{})
$MyShared.Text = "Parent text"
Создаем новую сессию (RunSpace):
$bgRunspace = [RunSpaceFactory]::CreateRunspace()
$bgRunspace.ApartmentState = "STA"
$bgRunspace.ThreadOptions = "ReuseThread"
$bgRunspace.Open()
Связываем с созданной ранее
синхронизированной хэш-таблицей:
$bgRunspace.SessionStateProxy.setVariable("MyShared", $MyShared)
Теперь у нас есть отдельный поток, синхронизированная
переменная, которую мы можем использовать как родительском, так и дочернем
потоке. Для запуска команд в дочернем потоке воспользуемся классом [PowerShell].
Он ассоциируется с нашим RunSpace и с помощью метода «BeginInvoke()» может выполнять любой скрипт, переданный ему:
$bgPowerShell = [PowerShell]::Create()
$bgPowerShell.Runspace = $bgRunspace
$bgPowerShell.AddScript({$MyShared.Text = "Child text"}).BeginInvoke()
Ну и пример использования:
#Generated Form Function
function
GenerateForm {
########################################################################
# Code Generated By: SAPIEN
Technologies PrimalForms (Community Edition) v1.0.10.0
# Generated On: 27.12.2011 9:04
########################################################################
#region
Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion
#region
Generated Form Objects
$form1
= New-Object
System.Windows.Forms.Form
$progressBar1 = New-Object
System.Windows.Forms.ProgressBar
$textBox1 = New-Object
System.Windows.Forms.TextBox
$button1
= New-Object
System.Windows.Forms.Button
$timer1
= New-Object
System.Windows.Forms.Timer
$InitialFormWindowState = New-Object
System.Windows.Forms.FormWindowState
#endregion
Generated Form Objects
# синхронизированная хэш-таблица
$MyShared = [HashTable]::Synchronized(@{})
# сохраняем ссылку на форму
$MyShared.Form = $form1
# "длительная"
команда
$bgCommand = {
$MyShared.Stop = $false
$MyShared.Form.Controls["progressBar1"].Maximum = $MyShared.list.length
foreach ($el in $MyShared.list) {
$MyShared.Form.Controls["textBox1"].Text += $MyShared.Text + ":
$el`r`n"
$MyShared.Form.Controls["progressBar1"].Value = $el
sleep 2
}
$MyShared.Stop = $true
}
$handler_timer1_Tick=
{
if ($MyShared.Stop)
{
$bgRunspace.Close()
$textBox1.Text += "Stop"
$timer1.Enabled = $false
$progressBar1.Value = 0
}
}
$handler_button1_Click=
{
$MyShared.list = 1..10
$MyShared.Text = "Some
text"
$textBox1.Text = ""
$progressBar1.Value = 0
# если надо использовать
внешний модуль в RunSpace
# $initial =
[Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
# $initial.ImportPSModule(("Some_module_path",...))
# $bgRunspace =
[RunSpaceFactory]::CreateRunspace($initial)
$bgRunspace = [RunSpaceFactory]::CreateRunspace()
$bgRunspace.ApartmentState = "STA"
$bgRunspace.ThreadOptions = "ReuseThread"
$bgRunspace.Open()
$bgRunspace.SessionStateProxy.setVariable("MyShared", $MyShared)
$bgPowerShell = [PowerShell]::Create()
$bgPowerShell.Runspace = $bgRunspace
$bgPowerShell.AddScript($bgCommand).BeginInvoke()
$timer1.Enabled = $true
}
$OnLoadForm_StateCorrection=
{#Correct
the initial state of the form to prevent the .Net maximized form issue
$form1.WindowState = $InitialFormWindowState
}
#----------------------------------------------
#region
Generated Form Code
$System_Drawing_Size = New-Object
System.Drawing.Size
$System_Drawing_Size.Height = 263
$System_Drawing_Size.Width = 274
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode
= 0
$form1.Name = "form1"
$form1.Text = "Primal
Form"
$progressBar1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object
System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 246
$progressBar1.Location =
$System_Drawing_Point
$progressBar1.Name = "progressBar1"
$System_Drawing_Size = New-Object
System.Drawing.Size
$System_Drawing_Size.Height = 10
$System_Drawing_Size.Width = 253
$progressBar1.Size = $System_Drawing_Size
$progressBar1.Step = 1
$progressBar1.TabIndex =
2
$form1.Controls.Add($progressBar1)
$textBox1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object
System.Drawing.Point
$System_Drawing_Point.X = 13
$System_Drawing_Point.Y = 42
$textBox1.Location =
$System_Drawing_Point
$textBox1.Multiline =
$True
$textBox1.Name = "textBox1"
$textBox1.ScrollBars =
2
$System_Drawing_Size = New-Object
System.Drawing.Size
$System_Drawing_Size.Height = 196
$System_Drawing_Size.Width = 251
$textBox1.Size = $System_Drawing_Size
$textBox1.TabIndex =
1
$form1.Controls.Add($textBox1)
$button1.DataBindings.DefaultDataSourceUpdateMode
= 0
$System_Drawing_Point = New-Object
System.Drawing.Point
$System_Drawing_Point.X = 189
$System_Drawing_Point.Y = 13
$button1.Location
= $System_Drawing_Point
$button1.Name
= "button1"
$System_Drawing_Size = New-Object
System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 75
$button1.Size
= $System_Drawing_Size
$button1.TabIndex
= 0
$button1.Text
= "button1"
$button1.UseVisualStyleBackColor
= $True
$button1.add_Click($handler_button1_Click)
$form1.Controls.Add($button1)
$timer1.Interval
= 1000
$timer1.add_Tick($handler_timer1_Tick)
#endregion
Generated Form Code
#Save the initial state of the
form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct
the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null
} #End Function
#Call the Function
GenerateForm
Возможно кому-нибудь будет полезно )
Спасибо!!! Очень пригодилось!
ОтветитьУдалить