我正在尝试向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会停止脚本内的所有处理,直到表单关闭。
答案 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,它具有水平,垂直和圆形进度条。