Windows窗体中的Powershell进度条

Windows窗体中的Powershell进度条,powershell,Powershell,我正在尝试向powershell中的窗体添加进度条。我不想使用PowerShell的Write Progress cmdlet(因为当我从命令行运行脚本时,它会显示一个基于文本的进度条,而我总是希望看到一个基于表单/图形的进度条) 我试过这个,它似乎有效(在线找到): 但是,我不希望事件更新进度条(正如上面示例中的$timer1_OnTic一样),我希望通过在整个脚本中调用来更新进度条,例如: $progressBar1.PerformStep() 或 因此,每当我调用PerformStep(

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

我试过这个,它似乎有效(在线找到):

但是,我不希望事件更新进度条(正如上面示例中的$timer1_OnTic一样),我希望通过在整个脚本中调用来更新进度条,例如:

$progressBar1.PerformStep()

因此,每当我调用PerformStep()或更改progressBar的值时,我似乎需要某种后台工作程序来更新进度条


调用ShowDialog将停止脚本内的所有处理,直到表单关闭。

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


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

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

e、 g

#定义共享变量
$sharedData=[HashTable]::已同步(@{});
$sharedData.Progress=0;
$sharedData.state=0;
$sharedData.EnableTimer=$true;
#设置运行空间(WPF需要STA)
$rs=[RunSpaceFactory]::CreateRunSpace();
$rs.ApartmentState=“STA”;
$rs.ThreadOptions=“ReuseThread”;
$rs.Open();
#将共享变量配置为可从两侧访问(父运行空间和子运行空间)
$rs.SessionStateProxy.setVariable(“sharedData”,$sharedData);
#定义要在子运行空间中运行的代码
$script={
添加类型-程序集表示框架;
添加类型-组件表示核心;
添加类型-组装WindowsBase;
[xml]$xaml=@”
你好,世界
"@
#处理上面的xaml
$reader=New Object System.Xml.XmlNodeReader$xaml;
$dialog=[Windows.Markup.XamlReader]::加载($reader);
#获取进度条的句柄
$progBar=$dialog.FindName(“ProgressComplete”);
$progBar.Value=0;
#定义要在每个间隔运行的代码(更新条形图)
#别忘了包括一种停止脚本的方法
$scriptBlock={
如果($sharedData.EnableTimer=$false){
$timer.IsEnabled=$false;
$dialog.Close();
}
$progBar.value=$sharedData.Progress;
}
#在计时器上,在每个“滴答声”上运行脚本
$dialog.Add_SourceInitialized({
$timer=新对象System.Windows.Threading.DispatherTimer;
$timer.Interface=[TimeSpan]“0:0:0.50”;
$timer.Add_Tick($scriptBlock);
$timer.Start();
如果(!$timer.IsEnabled){
$dialog.Close();
}
});
#启动计时器并显示对话框
&$scriptBlock;
$dialog.ShowDialog()| out null;
}
$ps=[PowerShell]::Create();
$ps.Runspace=$rs;
$ps.AddScript($script).BeginInvoke();
#如果需要GUI中的数据,可以通过$sharedData变量进行访问
写入输出$sharedData;
如果您尝试此代码,在显示对话框后,您可以通过设置
$sharedData.progress


这使我能够为工具编写大量对话框,我受我们的基础设施的限制,无法在运行空间中使用powershell,WPF似乎比表单工作得更好。

看看它有水平、垂直和圆形进度条。

谢谢,Show()方法做到了这一点。非常感谢。虽然此链接可以回答问题,但最好在此处包含答案的基本部分,并提供链接供参考。如果链接页面发生更改,则仅链接的答案可能无效。
$progressBar1.PerformStep()
$progressBar1.Value = 10
# 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;