提问人:David FJ 提问时间:11/17/2023 更新时间:11/17/2023 访问量:31
我在尝试创建带有可顺利更新的进度条的 powershell gui 时遇到问题
I'm having problems trying to create a powershell gui with a progress bar that updates smoothly
问:
我知道这是一个被广泛讨论的问题,我花了一周的大部分时间在谷歌上搜索和尝试,但无济于事......现在请放轻松!我不是这个powershell云雀的佼佼者,但我一直在努力获得一个简单的GUI,允许用户根据收集到的一些数据进行交互和创建输出。我有点让它工作,但数据收集大约需要 15 分钟,所以我想要一个进度条,这就是一切出错的地方!我创建了 prog 栏,它只会在数据函数完成时更新。我意识到我需要尝试找出跑道:(几天后,我有一个运行runspaces的脚本,但我仍然无法让它:(更新进度条。我敢肯定,你们中的一个聪明人会立即拉出我的代码,并向我展示它做得有多糟糕......正如你们中的一些人可能认识到的那样,最终结果是基于 https://www.foxdeploy.com/blog/part-v-powershell-guis-responsive-apps-with-progress-bars.html。那是在多次迭代尝试其他人的解决方案无济于事之后。我试图大规模简化我的代码,只处理手头的直接问题 - 这就是我将在下面添加的内容。 因此,如果你们中的任何一个善良的人能清楚地向我指出我是多么的白痴,以及我哪里出了问题,我将不胜感激:)请记住,您可能需要慢慢呼吸并大写,因为我显然很难学习......好吧,我感觉就像这周在该死的跑道上撞墙之后!:) 提前感谢您:)的任何帮助 哦,我提前向那些会回复的人道歉 - “只是搜索 - 看这里是你在另一个链接中的答案”我试过了,但我仍然把头撞在墙上!:)
所以这里是 - 我的时髦代码 - 请善待!:)(一些证据仍然在那里徘徊,证明我在变量类型和一些弹出窗口上搞砸了,以确认进度等)
$
`global:NumOfDays = 0
$global:selectcb1 = "Y"
$global:selectcb2 = "Y"
$global:selectcb3 = "Y"
$global:outputArr = @()
#create synchash
$global:syncHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$global:syncHash)
Add-Type -AssemblyName PresentationCore, PresentationFramework
#create main process
$psCmd = [PowerShell]::Create().AddScript({
[xml]$xaml = @"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="Data Tool" WindowStartupLocation = "CenterScreen"
Width = "900" Height = "600" ShowInTaskbar = "True">
<Grid Margin="3,0,137,1">
<CheckBox Name="CB1" IsChecked="True" HorizontalAlignment="Left" VerticalAlignment="Top" Content="CB 1" Margin="40,110,0,0"/>
<CheckBox Name="CB2" IsChecked="True" HorizontalAlignment="Left" VerticalAlignment="Top" Content="CB 2" Margin="40,150,0,0"/>
<CheckBox Name="CB3" IsChecked="True" HorizontalAlignment="Left" VerticalAlignment="Top" Content="CB 3" Margin="40,190,0,0"/>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" TextWrapping="Wrap" Text="Explain stuff" Margin="47,30,0,0" Width="271" Height="67" FontWeight="SemiBold"/>
<Button Name="Create" Content="Create Output" HorizontalAlignment="Left" VerticalAlignment="Top" Width="139" Margin="350,400,0,0" Height="22"/>
<Button Name="Quit" Content="Quit" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" Margin="600,500,0,0" Height="22"/>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" TextWrapping="Wrap" Text="explain slider" Margin="200,320,0,0" Width="500" Height="67" />
<DockPanel VerticalAlignment="Center" Margin="60,150,0,0">
<TextBox Name="slValue" Text="{Binding ElementName=slider, Path=Value, UpdateSourceTrigger=PropertyChanged}" DockPanel.Dock="Right" TextAlignment="Right" Width="40" />
<Slider Name="slider" Minimum = "5" Maximum="365" TickPlacement="BottomRight" TickFrequency="5" IsSnapToTickEnabled="True" />
</DockPanel>
<ProgressBar Name="ProgBar" Maximum="100" HorizontalAlignment="Left" Height="19" VerticalAlignment="Top" Width="408" Margin="372,41,0,0"/>
<TextBlock Text="{Binding ElementName=ProgBar, Path=Value, StringFormat={}{0:0}%}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="572,41,0,0" />
<TextBlock Name="dataprogress" HorizontalAlignment="Left" VerticalAlignment="Top" Text="Progress - " Margin="498,15,0,0"/>
</Grid>
</Window>
"@
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$syncHash.Window=[Windows.Markup.XamlReader]::Load( $reader )
[xml]$XAML = $xaml
$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | %{
#Find all of the form types and add them as members to the synchash
$global:syncHash.Add($_.Name,$global:syncHash.Window.FindName($_.Name) )
}
# Create second process handler
$global:JobCleanup = [hashtable]::Synchronized(@{})
$global:Jobs = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList))
#region Background runspace to clean up jobs
$jobCleanup.Flag = $True
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("jobCleanup",$jobCleanup)
$newRunspace.SessionStateProxy.SetVariable("jobs",$jobs)
$jobCleanup.PowerShell = [PowerShell]::Create().AddScript({
#Routine to handle completed runspaces
Do {
Foreach($runspace in $jobs) {
If ($runspace.Runspace.isCompleted) {
[void]$runspace.powershell.EndInvoke($runspace.Runspace)
$runspace.powershell.dispose()
$runspace.Runspace = $null
$runspace.powershell = $null
}
}
#Clean out unused runspace jobs
$temphash = $jobs.clone()
$temphash | Where {
$_.runspace -eq $Null
} | ForEach {
$jobs.remove($_)
}
Start-Sleep -Seconds 1
} while ($jobCleanup.Flag)
})
$jobCleanup.PowerShell.Runspace = $newRunspace
$jobCleanup.Thread = $jobCleanup.PowerShell.BeginInvoke()
#endregion Background runspace to clean up jobs
# controls ###################################
$syncHash.Quit.add_click({
#[System.Windows.MessageBox]::Show('Quit')
$global:syncHash.Window.Close()
$global:syncHash.Clear()
$global:syncHash.Quit
$newRunspace.Clear()
$newRunspace.Dispose()
#Exit
})
$global:syncHash.CB1.Add_Checked({
$global:selectcb1 = "Y"
#[System.Windows.MessageBox]::Show($selectcb1)
})
$global:syncHash.CB1.Add_Unchecked({
$global:selectcb1 = "N"
#[System.Windows.MessageBox]::Show($selectcb1)
})
$global:syncHash.CB2.Add_Checked({
$global:selectcb2 = "Y"
#[System.Windows.MessageBox]::Show($selectcb2)
})
$global:syncHash.CB2.Add_Unchecked({
$global:selectcb2 = "N"
#[System.Windows.MessageBox]::Show($selectcb2)
})
$global:syncHash.CB3.Add_Checked({
$global:selectcb3 = "Y"
#[System.Windows.MessageBox]::Show($selectcb3)
})
$global:syncHash.CB3.Add_Unchecked({
$global:selectcb3 = "N"
#[System.Windows.MessageBox]::Show($selectcb3)
})
$global:syncHash.slValue.add_TextChanged({
$global:NumOfDays = $global:syncHash.slValue.Text
#[System.Windows.MessageBox]::Show($NumOfDays)
})
$global:syncHash.create.add_click({
[System.Windows.MessageBox]::Show('create')
})
$global:syncHash.Window.Add_ContentRendered({
[System.Windows.MessageBox]::Show('gather')
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("SyncHash",$SyncHash)
$PowerShell = [PowerShell]::Create().AddScript({
###############################################
Function Update-Window {
Param (
$Control,
$Property,
$Value,
[switch]$AppendContent
)
# This is kind of a hack, there may be a better way to do this
If ($Property -eq "Close") {
$syncHash.Window.Dispatcher.invoke([action]{$syncHash.Window.Close()},"Normal")
Return
}
# This updates the control based on the parameters passed to the function
$syncHash.$Control.Dispatcher.Invoke([action]{
# This bit is only really meaningful for the TextBox control, which might be useful for logging progress steps
If ($PSBoundParameters['AppendContent']) {
$syncHash.$Control.AppendText($Value)
} Else {
$syncHash.$Control.$Property = $Value
}
}, "Normal")
}
###############################################
[System.Windows.MessageBox]::Show('gathering')
for ($i = 1 ; $i -le 100 ; $i++) {
Start-Sleep -milliseconds 100
#$global:SyncHash.Window.Dispatcher.Invoke([Action]{$global:SyncHash.ProgBar.Value = $i})
update-window -Control ProgrBar -Property Value -Value $i
}
})
###############################################
$PowerShell.Runspace = $newRunspace
[void]$Jobs.Add((
[pscustomobject]@{
PowerShell = $PowerShell
Runspace = $PowerShell.BeginInvoke()
}
))
})
#region Window Close
$syncHash.Window.Add_Closed({
Write-Verbose 'Halt runspace cleanup job processing'
$jobCleanup.Flag = $False
#Stop all runspaces
$jobCleanup.PowerShell.Dispose()
$PowerShell.Invoke()
[System.Windows.MessageBox]::Show('done')
})
##############################################
$global:syncHash.Window.ShowDialog() | Out-Null
$global:syncHash.Error = $Error
`
答: 暂无答案
评论