Windows窗体中的Powershell进度条

时间:2011-04-13 01:18:10

标签: powershell

我正在尝试向powershell中的表单添加进度条。我不想使用PowerShell的Write-Progress cmdlet(因为当我从命令行运行脚本时,它显示了一个基于文本的进度条,我总是想要一个基于表单/图形的栏。)

我已经尝试过了,它似乎有效(在网上找到):

[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 个答案:

答案 0 :(得分:6)

如果我理解正确,您应该能够将ShowDialog()更改为Show(),这将显示Dialog而不会阻止您的脚本。然后,您可以继续执行并更新进度条。

尽管如此,您可能会对表单缺乏交互性感到失望。

答案 1 :(得分:3)

我取得了一些成功的方法是为GUI使用子运行空间(在本例中为WPF),因此它不会锁定脚本。可以通过会话状态代理在父运行空间和子运行空间中访问数据。

e.g。

# 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似乎比表单更好。

答案 2 :(得分:0)

看看Posh Progress Bar,它具有水平,垂直和圆形进度条。