【问题标题】:Powershell Progress Bar in Windows FormsWindows 窗体中的 Powershell 进度条
【发布时间】:2018-08-02 17:38:31
【问题描述】:

我正在尝试向 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 会停止脚本内的所有处理,直到表单关闭。

【问题讨论】:

    标签: powershell


    【解决方案1】:

    如果我理解正确,您应该可以将 ShowDialog() 更改为 Show(),这样会在不阻塞脚本的情况下显示对话框。然后您可以继续执行并更新进度条。

    您可能会对表单缺乏交互性感到失望。

    【讨论】:

    • 谢谢,Show() 方法做到了。非常感谢。
    【解决方案2】:

    我取得了一些成功的方法是为 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 似乎比表单工作得更好。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-16
      • 1970-01-01
      • 2019-01-20
      相关资源
      最近更新 更多