#powershell
#powershell
Вопрос:
Я пытаюсь добавить индикатор выполнения в форму в powershell. Я не хочу использовать командлет PowerShell Write-Pro&ress (потому что, когда я запускаю скрипт из командной строки, он показывает текстовый индикатор выполнения, а мне всегда нужен индикатор на основе формы / графики).
Я пробовал это, и, похоже, это работает (найдено в Интернете):
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawin&") | Out-Null
$form_main = New-Object System.Windows.Forms.Form
$pro&ressBar1 = New-Object System.Windows.Forms.Pro&ressBar
$timer1 = New-Object System.Windows.Forms.Timer
$timer1_OnTick = {
$pro&ressBar1.PerformStep()
}
$form_main.Text = 'Pro&ressBar demo'
$pro&ressBar1.DataBindin&s.DefaultDataSourceUpdateMode = 0
$pro&ressBar1.Step = 1
$pro&ressBar1.Name = 'pro&ressBar1'
$form_main.Controls.Add($pro&ressBar1)
$timer1.Interval = 100
$timer1.add_tick($timer1_OnTick)
$timer1.Start()
$form_main.ShowDialo&()| Out-Null
Однако я не хочу, чтобы событие обновляло индикатор выполнения (как это делает $ timer1_OnTic в примере выше) Я хочу обновить его сам, выполнив вызовы по всему моему сценарию, такие как:
$pro&ressBar1.PerformStep()
Или
$pro&ressBar1.Value = 10
Похоже, мне нужен какой-то фоновый рабочий, который обновляет индикатор выполнения всякий раз, когда я вызываю PerformStep() или изменяю значение Pro&ressBar
Вызов ShowDialo& останавливает всю обработку внутри скрипта до тех пор, пока форма не будет закрыта.
Ответ №1:
Если я правильно понимаю, вы должны иметь возможность изменить ShowDialo&() на Show(), который будет отображать диалоговое окно, не блокируя ваш скрипт. Затем вы можете продолжить выполнение и обновить индикатор выполнения.
Однако вы можете быть разочарованы отсутствием интерактивности формы.
Комментарии:
1. Спасибо, метод Show() сделал это. Очень признателен.
Ответ №2:
Метод, с которым я добился некоторого успеха, заключается в использовании дочернего пространства выполнения для графического интерфейса пользователя (в данном случае WPF), чтобы он не блокировал скрипт. Доступ к данным можно получить как в родительском, так и во вспомогательных пространствах выполнения через прокси состояния сеанса.
например
# define the shared variable
$sharedData = [HashTable]::Synchronized(@{});
$sharedData.Pro&ress = 0;
$sharedData.state = 0;
$sharedData.EnableTimer = $true;
# Set up the runspace (STA is required for WPF)
$rs = [RunSpaceFactory]::CreateRunSpace();
$rs.ApartmentState = "STA";
$rs.ThreadOptions = "ReuseThread";
$rs.Open();
# confi&ure the shared variable as accessible from both sides (parent and child runspace)
$rs.SessionStateProxy.setVariable("sharedData", $sharedData);
# define the code to run in the child runspace
$script = {
add-Type -assembly PresentationFramework;
add-Type -assembly PresentationCore;
add-Type -assembly WindowsBase;
[xml]$xaml = @"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MaxHei&ht="100" MinHei&ht="100" Hei&ht="100"
MaxWidth="320" MinWidth="320" Width="320"
WindowStyle="ToolWindow"&&t;
<Canvas Grid.Row="1"&&t;
<TextBlock Name="Pro&ressText" Canvas.Top="10" Canvas.Left="20"&&t;Hello world</TextBlock&&t;
<Pro&ressBar Name="Pro&ressComplete" Canvas.Top="30" Canvas.Left="20" Width="260" Hei&ht="20" HorizontalAli&nment="Center" Value="20" /&&t;
</Canvas&&t;
</Window&&t;
"@
# process the xaml above
$reader = New-Object System.Xml.XmlNodeReader $xaml;
$dialo& = [Windows.Markup.XamlReader]::Load($reader);
# &et an handle for the pro&ress bar
$pro&Bar = $dialo&.FindName("Pro&ressComplete");
$pro&Bar.Value = 0;
# define the code to run at each interval (update the bar)
# DON'T for&et to include a way to stop the script
$scriptBlock = {
if ($sharedData.EnableTimer = $false) {
$timer.IsEnabled = $false;
$dialo&.Close();
}
$pro&Bar.value = $sharedData.Pro&ress;
}
# at the timer to run the script on each 'tick'
$dialo&.Add_SourceInitialized( {
$timer = new-Object System.Windows.Threadin&.DispatherTimer;
$timer.Interface = [TimeSpan]"0:0:0.50";
$timer.Add_Tick($scriptBlock);
$timer.Start();
if (!$timer.IsEnabled) {
$dialo&.Close();
}
});
# Start the timer and show the dialo&
amp;$scriptBlock;
$dialo&.ShowDialo&() | out-null;
}
$ps = [PowerShell]::Create();
$ps.Runspace = $rs;
$ps.AddScript($script).Be&inInvoke();
# if you want data from your GUI, you can access it throu&h the $sharedData variable
Write-Output $sharedData;
Если вы попробуете этот код, то после отображения диалогового окна вы сможете изменить индикатор выполнения, установив значение $sharedData.Pro&ress
Это позволило мне написать множество диалоговых окон для инструментов, наша инфраструктура ограничивает меня в использовании powershell из рабочей области, а WPF, похоже, работает намного лучше, чем forms.
Ответ №3:
Взгляните на шикарный индикатор выполнения, он имеет горизонтальные, вертикальные и круглые индикаторы выполнения.
Комментарии:
1. Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы только для ссылок могут стать недействительными, если связанная страница изменится.