【发布时间】:2020-09-17 08:04:06
【问题描述】:
我无法让 WPF 窗口继续从 PowerShell 更新,也不会冻结。
这个想法是,当我单击按钮时,将运行一些函数来更新进度条的值。但是无论我使用哪种方法或指南,我都无法让它发挥作用。进度条正在更新并在任务完成时填充到 100%。但在操作过程中,窗口冻结。我可以让窗口不冻结的唯一方法是在updateblock 中进行简单的增值。但我需要能够运行不同的功能并一次又一次地更新进度条。
我需要做什么才能从 Click-event 运行函数或脚本块,以使窗口不会冻结并且进度条会更新?
PowerShell 代码:
Add-Type -Assembly PresentationFramework
$syncHash = [hashtable]::Synchronized( @{} )
$syncHash.Counter = 0.0
$syncHash.Do = {
param ( $syncHash, $ToDo )
$rsR = [runspacefactory]::CreateRunspace()
$rsR.ApartmentState = "STA"
$rsR.ThreadOptions = "ReuseThread"
$rsR.Open()
$rsR.SessionStateProxy.SetVariable( "syncHash", $syncHash )
$c = [powershell]::Create().AddScript( $ToDo )
$c.Runspace = $rsR
$h = $c.BeginInvoke()
do { start-sleep -millisecond 10 } until ( $h.IsCompleted -eq $true )
$c.EndInvoke( $h )
$rsR.Close()
$rsR.Dispose()
}
$syncHash.Window = [Windows.Markup.XamlReader]::Load( ( New-Object System.Xml.XmlNodeReader ( [xml]( Get-Content .\tt.xml ) ) ) )
$syncHash.Button = $syncHash.Window.FindName( "Button" )
$syncHash.Progress = $syncHash.Window.FindName( "Progress" )
$Timer = New-Object System.Windows.Threading.DispatcherTimer
$Task = { 1..100 | % { start-sleep -millisecond 10; $syncHash.Counter = $_ } }
$syncHash.Button.Add_Click( { Something } )
$syncHash.Window.Add_SourceInitialized( {
$Timer.Start()
$Timer.Add_Tick( $UpdateBlock )
$Timer.Interval = [TimeSpan]"0:0:0.01"
} )
function Something
{
& $syncHash.Do $syncHash $Task
}
$UpdateBlock =`
{
$syncHash.Window.Resources["Progress"] = [double]$syncHash.Counter
$syncHash.Window.Resources["PbText"] = "$( $syncHash.Counter ) %"
}
[void]$syncHash.Window.ShowDialog()
XAML 代码:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
Topmost="True"
WindowStartupLocation="CenterScreen"
SizeToContent="WidthAndHeight">
<Window.Resources>
<system:Double x:Key="Progress">0.0</system:Double>
<system:String x:Key="PbText"></system:String>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Click" Name="Button"/>
<Grid Grid.Row="1">
<ProgressBar Name="Progress" Minimum="0" Value="{DynamicResource Progress}" Width="230"/>
<TextBlock Text="{DynamicResource PbText}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
</Window>
【问题讨论】:
-
你已经有一个额外的线程(运行空间),但你只是没有充分利用它。您打开另一个线程,然后将您的主/GUI线程发送到睡眠状态,直到任务完成......而是将进度存储在您的
$syncHash中具有INotifyPropertyChanged的对象中,以便您可以触发事件以更新进度条发生变化而不是等待/休眠。 -
我试图得到这个,但我要么不明白你要解释什么,要么不明白如何实现它:(
标签: wpf powershell progress-bar