Индикатор выполнения Powershell в Windows Forms

#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. Хотя эта ссылка может дать ответ на вопрос, лучше включить сюда основные части ответа и предоставить ссылку для справки. Ответы только для ссылок могут стать недействительными, если связанная страница изменится.