From afd0a36003bdeb327e0cbc4b5cdaf7ce71a638d3 Mon Sep 17 00:00:00 2001 From: Chris Titus Date: Wed, 1 Jul 2026 22:55:35 -0500 Subject: [PATCH] Replace install render timer with dispatcher callbacks --- .../Start-WinUtilInstallAppRendering.ps1 | 54 ++++++++++--------- pester/install-rendering.Tests.ps1 | 13 ++--- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/functions/private/Start-WinUtilInstallAppRendering.ps1 b/functions/private/Start-WinUtilInstallAppRendering.ps1 index b15ef7aa..afface44 100644 --- a/functions/private/Start-WinUtilInstallAppRendering.ps1 +++ b/functions/private/Start-WinUtilInstallAppRendering.ps1 @@ -13,6 +13,28 @@ function Invoke-WinUtilInstallAppRenderBatch { } } +function Complete-WinUtilInstallAppRendering { + $sync.InstallAppEntriesRendered = $true + Write-WinUtilPerformanceCheckpoint -Name "Install app entries rendered" +} + +function Invoke-WinUtilInstallAppRenderNextBatch { + if ($sync.InstallAppRenderQueue.Count -gt 0) { + $categoryBatch = $sync.InstallAppRenderQueue.Dequeue() + Invoke-WinUtilInstallAppRenderBatch -CategoryBatch $categoryBatch + } + + if ($sync.InstallAppRenderQueue.Count -gt 0) { + $sync.Form.Dispatcher.BeginInvoke( + [System.Windows.Threading.DispatcherPriority]::Background, + [action]{ Invoke-WinUtilInstallAppRenderNextBatch } + ) | Out-Null + return + } + + Complete-WinUtilInstallAppRendering +} + function Start-WinUtilInstallAppRendering { if ($null -eq $sync.InstallAppRenderQueue) { return @@ -20,30 +42,11 @@ function Start-WinUtilInstallAppRendering { $sync.InstallAppEntriesRendered = $false - if ($sync.Form -and $sync.Form.Dispatcher -and ("System.Windows.Threading.DispatcherTimer" -as [type])) { - $timer = New-Object System.Windows.Threading.DispatcherTimer - $timer.Interval = [TimeSpan]::FromMilliseconds(1) - $timer.Add_Tick({ - param($sender) - - $dispatcherTimer = [System.Windows.Threading.DispatcherTimer]$sender - $dispatcherTimer.Stop() - - if ($sync.InstallAppRenderQueue.Count -gt 0) { - $categoryBatch = $sync.InstallAppRenderQueue.Dequeue() - Invoke-WinUtilInstallAppRenderBatch -CategoryBatch $categoryBatch - } - - if ($sync.InstallAppRenderQueue.Count -gt 0) { - $dispatcherTimer.Start() - return - } - - $sync.InstallAppEntriesRendered = $true - Write-WinUtilPerformanceCheckpoint -Name "Install app entries rendered" - }) - $sync.InstallAppRenderTimer = $timer - $timer.Start() + if ($sync.Form -and $sync.Form.Dispatcher) { + $sync.Form.Dispatcher.BeginInvoke( + [System.Windows.Threading.DispatcherPriority]::Background, + [action]{ Invoke-WinUtilInstallAppRenderNextBatch } + ) | Out-Null return } @@ -52,6 +55,5 @@ function Start-WinUtilInstallAppRendering { Invoke-WinUtilInstallAppRenderBatch -CategoryBatch $categoryBatch } - $sync.InstallAppEntriesRendered = $true - Write-WinUtilPerformanceCheckpoint -Name "Install app entries rendered" + Complete-WinUtilInstallAppRendering } diff --git a/pester/install-rendering.Tests.ps1 b/pester/install-rendering.Tests.ps1 index a264e732..d680c1c2 100644 --- a/pester/install-rendering.Tests.ps1 +++ b/pester/install-rendering.Tests.ps1 @@ -15,21 +15,22 @@ Describe "Install app rendering startup contract" { $categoryScript | Should -Match 'Pre-group apps by category before creating WPF controls' } - It "renders queued apps through a dispatcher timer when a form dispatcher exists" { + It "renders queued apps through dispatcher callbacks when a form dispatcher exists" { $renderScript = Get-Content -Path (Join-Path $script:repoRoot "functions\private\Start-WinUtilInstallAppRendering.ps1") -Raw - $renderScript | Should -Match 'System\.Windows\.Threading\.DispatcherTimer' + $renderScript | Should -Match 'Dispatcher\.BeginInvoke' + $renderScript | Should -Match 'Invoke-WinUtilInstallAppRenderNextBatch' $renderScript | Should -Match 'Initialize-InstallAppEntry' $renderScript | Should -Match 'Install app entries rendered' } - It "does not rely on local timer variables after the dispatcher tick fires" { + It "does not use dispatcher timers for deferred install rendering" { $renderScript = Get-Content -Path (Join-Path $script:repoRoot "functions\private\Start-WinUtilInstallAppRendering.ps1") -Raw - $renderScript | Should -Match 'param\(\$sender\)' - $renderScript | Should -Match '\$dispatcherTimer = \[System\.Windows\.Threading\.DispatcherTimer\]\$sender' + $renderScript | Should -Not -Match 'DispatcherTimer' + $renderScript | Should -Not -Match '\$timer' + $renderScript | Should -Not -Match '\$dispatcherTimer' $renderScript | Should -Not -Match '\$timer\.Stop\(\)' - $renderScript | Should -Match '\$dispatcherTimer\.Start\(\)' $renderScript | Should -Not -Match '& \$renderCategory' }