Индикатор выполнения Powershell в Windows Forms - PullRequest
5 голосов
/ 13 апреля 2011

Я пытаюсь добавить индикатор прогресса в форму в powershell. Я не хочу использовать командлет PowerShell Write-Progress (потому что, когда я запускаю скрипт из командной строки, он показывает текстовый индикатор выполнения, и мне всегда нужна форма / графическая панель).

Я пробовал это, и, кажется, работает (найдено в Интернете):

[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null

$form_main = New-Object System.Windows.Forms.Form
$progressBar1 = New-Object System.Windows.Forms.ProgressBar
$timer1 = New-Object System.Windows.Forms.Timer

$timer1_OnTick = {
  $progressBar1.PerformStep()
}

$form_main.Text = 'ProgressBar demo'

$progressBar1.DataBindings.DefaultDataSourceUpdateMode = 0
$progressBar1.Step = 1
$progressBar1.Name = 'progressBar1'

$form_main.Controls.Add($progressBar1)

$timer1.Interval = 100
$timer1.add_tick($timer1_OnTick)
$timer1.Start()

$form_main.ShowDialog()| Out-Null

Однако я не хочу, чтобы событие обновляло индикатор выполнения (как это делает $ timer1_OnTic в приведенном выше примере), я хочу обновить его сам, совершая вызовы по всему сценарию, такие как:

$progressBar1.PerformStep()

Или

$progressBar1.Value = 10

Так что, похоже, мне нужен какой-то фоновый рабочий, который обновляет индикатор выполнения всякий раз, когда я выполняю вызовы PerformStep () или изменяю значение progressBar

Вызов ShowDialog останавливает всю обработку внутри скрипта, пока форма не будет закрыта.

Ответы [ 3 ]

6 голосов
/ 13 апреля 2011

Если я правильно понимаю, вы сможете изменить ShowDialog () на Show (), который будет отображать диалог без блокировки вашего скрипта. Затем вы можете продолжить выполнение и обновить индикатор выполнения.

Вы можете быть разочарованы отсутствием интерактивности формы.

3 голосов
/ 08 марта 2013

Метод, с которым у меня был некоторый успех, состоит в том, чтобы использовать дочернее пространство для GUI (в данном случае WPF), чтобы он не блокировал скрипт.Доступ к данным можно получить как в родительском, так и в подпространстве исполнения через прокси состояния сеанса.

например,

# define the shared variable
$sharedData = [HashTable]::Synchronized(@{});
$sharedData.Progress = 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();

# configure 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" 
  MaxHeight="100" MinHeight="100" Height="100" 
  MaxWidth="320" MinWidth="320" Width="320" 
  WindowStyle="ToolWindow">

<Canvas Grid.Row="1">
  <TextBlock Name="ProgressText" Canvas.Top="10" Canvas.Left="20">Hello world</TextBlock>
  <ProgressBar Name="ProgressComplete" Canvas.Top="30" Canvas.Left="20" Width="260" Height="20" HorizontalAlignment="Center" Value="20" />
</Canvas>

</Window>
"@

    # process the xaml above
    $reader = New-Object System.Xml.XmlNodeReader $xaml;
    $dialog = [Windows.Markup.XamlReader]::Load($reader);

    # get an handle for the progress bar
    $progBar = $dialog.FindName("ProgressComplete");
    $progBar.Value = 0;

    # define the code to run at each interval (update the bar)
    # DON'T forget to include a way to stop the script
    $scriptBlock = {
        if ($sharedData.EnableTimer = $false) {
            $timer.IsEnabled = $false;
            $dialog.Close();
        }

        $progBar.value = $sharedData.Progress;
    }

    # at the timer to run the script on each 'tick'
    $dialog.Add_SourceInitialized( {
        $timer = new-Object System.Windows.Threading.DispatherTimer;
        $timer.Interface = [TimeSpan]"0:0:0.50";
        $timer.Add_Tick($scriptBlock);
        $timer.Start();
        if (!$timer.IsEnabled) {
            $dialog.Close();
        }
    });

    # Start the timer and show the dialog
    &$scriptBlock;
    $dialog.ShowDialog() | out-null;
}

$ps = [PowerShell]::Create();
$ps.Runspace = $rs;
$ps.AddScript($script).BeginInvoke();

# if you want data from your GUI, you can access it through the $sharedData variable
Write-Output $sharedData;

Если вы попробуете этот код, после отображения диалогового окна вы можете изменить индикатор выполнения, установив значение $sharedData.Progress

Это позволиломне нужно написать множество диалогов для инструментов, наша инфраструктура заставляет меня использовать powershell из пространства выполнения, и кажется, что WPF работает намного лучше, чем формы.

0 голосов
/ 02 августа 2018

Взгляните на Шикарный индикатор выполнения , он имеет горизонтальный, вертикальный и круговой индикатор выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...