@@ -33,6 +33,8 @@ public sealed partial class FormMain : Form
3333 private readonly bool _shouldSaveOnClose ;
3434 private readonly bool _isRunningAsAdmin ;
3535 private readonly bool _restartingAsAdmin ;
36+ private Font ? _fontRegular ;
37+ private readonly Dictionary < string , Font > _fontCache = [ ] ;
3638
3739 // Store original FillWeight values to detect user modifications
3840 private readonly Dictionary < string , float > _originalFillWeights = [ ] ;
@@ -186,6 +188,8 @@ private void FormPrincipal_Load(object? sender, EventArgs e)
186188
187189 private void FormPrincipal_Shown ( object ? sender , EventArgs e )
188190 {
191+ _isInitializingColumns = true ;
192+
189193 try
190194 {
191195 // Restore window position/size/state from config
@@ -215,6 +219,10 @@ private void FormPrincipal_Shown(object? sender, EventArgs e)
215219 {
216220 // ignore restore failures
217221 }
222+ finally
223+ {
224+ _isInitializingColumns = false ;
225+ }
218226 }
219227
220228 private void UpdateFilterLists ( )
@@ -614,7 +622,7 @@ private void GridServs_ColumnHeaderMouseClick(object? sender, DataGridViewCellMo
614622 }
615623
616624 private void GridServs_ColumnWidthChanged ( object ? sender , DataGridViewColumnEventArgs e )
617- => BeginInvoke ( UpdateColumnHeaderHeight ) ;
625+ => BeginInvoke ( ( ) => UpdateColumnHeaderHeight ( ) ) ;
618626
619627 private void GridServs_ColumnDisplayIndexChanged ( object ? sender , DataGridViewColumnEventArgs e )
620628 => SaveColumnOrder ( ) ;
@@ -628,9 +636,9 @@ private async Task ShowColumnChooserDialogAsync()
628636
629637 using var dlg = new FormColumnChooser ( [ .. GridServs . Columns . Cast < DataGridViewColumn > ( ) ] , visibleColumns ) ;
630638
631- #pragma warning disable WFO5002
639+ #pragma warning disable WFO5002
632640 if ( await dlg . ShowDialogAsync ( this ) != DialogResult . OK )
633- #pragma warning restore WFO5002
641+ #pragma warning restore WFO5002
634642 return ;
635643
636644 // Update config with selected columns
@@ -673,10 +681,10 @@ private void ApplyColumnVisibility()
673681 /// Calculates and updates the column header height based on the maximum number of lines
674682 /// in visible column headers.
675683 /// </summary>
676- private void UpdateColumnHeaderHeight ( )
684+ private void UpdateColumnHeaderHeight ( bool force = false )
677685 {
678686 // Skip during initialization to avoid conflicts with auto-resize
679- if ( _isInitializingColumns )
687+ if ( _isInitializingColumns && ! force )
680688 return ;
681689
682690 try
@@ -685,7 +693,7 @@ private void UpdateColumnHeaderHeight()
685693
686694 using var g = GridServs . CreateGraphics ( ) ;
687695 var headerStyle = GridServs . ColumnHeadersDefaultCellStyle ;
688- var font = headerStyle . Font ;
696+ var font = headerStyle . Font ! ;
689697
690698 foreach ( DataGridViewColumn col in GridServs . Columns )
691699 {
@@ -1043,6 +1051,7 @@ private void BtnLoad_Click(object? sender, EventArgs e)
10431051
10441052 private async Task RefreshServiceListAsync ( )
10451053 {
1054+ _isInitializingColumns = true ;
10461055 BtnLoad . Enabled = false ;
10471056 var previousCursor = Cursor . Current ;
10481057 Cursor . Current = Cursors . WaitCursor ;
@@ -1075,7 +1084,7 @@ private async Task RefreshServiceListAsync()
10751084 // Update column header height after data is loaded and columns have their final widths
10761085 // Use a small delay to ensure all auto-resize operations are complete
10771086 await Task . Delay ( 50 ) ;
1078- UpdateColumnHeaderHeight ( ) ;
1087+ UpdateColumnHeaderHeight ( force : true ) ;
10791088
10801089 AppendLog ( $ "Loaded { _allServices . Count } services.") ;
10811090 }
@@ -1090,6 +1099,7 @@ private async Task RefreshServiceListAsync()
10901099 ProgressBar . Visible = false ;
10911100 UpdateActionButtonsEnabled ( ) ;
10921101 Cursor . Current = previousCursor ;
1102+ _isInitializingColumns = false ;
10931103 }
10941104 }
10951105
@@ -1199,29 +1209,6 @@ private void ApplyFilterAndSort()
11991209 _servicesList . ListChanged += ServicesList_ListChanged ;
12001210 serviceBindingSource . DataSource = _servicesList ;
12011211 serviceBindingSource . ResetBindings ( false ) ;
1202-
1203- // Ensure the DataGridView repaints so the sort glyph is shown/cleared immediately
1204- GridServs . Refresh ( ) ;
1205-
1206- // If we have a sorted column, invalidate its header to ensure glyph is painted
1207- if ( string . IsNullOrEmpty ( _sortPropertyName ) || _sortOrder == SortOrder . None )
1208- return ;
1209-
1210- var idx = GridServs . Columns . Cast < DataGridViewColumn > ( )
1211- . ToList ( )
1212- . FindIndex ( c => c . DataPropertyName == _sortPropertyName || c . Name == _sortPropertyName ) ;
1213-
1214- if ( idx < 0 )
1215- return ;
1216-
1217- GridServs . InvalidateColumn ( idx ) ;
1218-
1219- // additional aggressive repaints
1220- GridServs . Invalidate ( ) ;
1221- GridServs . Update ( ) ;
1222-
1223- // clear any selection that might leave header visually selected
1224- GridServs . ClearSelection ( ) ;
12251212 }
12261213
12271214 private void ServicesList_ListChanged ( object ? sender , ListChangedEventArgs e )
@@ -1362,8 +1349,9 @@ private void GridServs_CellFormatting(object? sender, DataGridViewCellFormatting
13621349 var item = _servicesList [ e . RowIndex ] ;
13631350 var row = GridServs . Rows [ e . RowIndex ] ;
13641351
1365- // Define a base font, which will be regular
1366- var baseFont = ( Font ? ) row . DefaultCellStyle . Font ?? GridServs . DefaultCellStyle . Font ; // Yes, this can be null
1352+ // Cache the base font to avoid recreating it every time
1353+ _fontRegular ??= new Font ( ( Font ? ) GridServs . Font ?? SystemFonts . DefaultFont , FontStyle . Regular ) ;
1354+
13671355 var style = FontStyle . Regular ;
13681356
13691357 // Check if the executable exists
@@ -1372,8 +1360,16 @@ private void GridServs_CellFormatting(object? sender, DataGridViewCellFormatting
13721360 if ( string . IsNullOrEmpty ( exePath ) || ! File . Exists ( exePath ) )
13731361 style |= FontStyle . Strikeout ;
13741362
1375- // Apply font style
1376- row . DefaultCellStyle . Font = new Font ( baseFont , style ) ;
1363+ // Use cached font or create and cache it
1364+ var cacheKey = style . ToString ( ) ;
1365+
1366+ if ( ! _fontCache . TryGetValue ( cacheKey , out var font ) )
1367+ {
1368+ font = new Font ( GridServs . Font ?? SystemFonts . DefaultFont , style ) ;
1369+ _fontCache [ cacheKey ] = font ;
1370+ }
1371+
1372+ row . DefaultCellStyle . Font = font ;
13771373
13781374 // Color the entire row by status
13791375 row . DefaultCellStyle . BackColor = item . GetStatus ( ) switch
@@ -1586,7 +1582,6 @@ private void FormPrincipal_FormClosing(object? sender, FormClosingEventArgs e)
15861582 {
15871583 // Save current window bounds/state to config
15881584 var rect = ( WindowState == FormWindowState . Normal ) ? Bounds : RestoreBounds ;
1589-
15901585 _appConfig . WindowLeft = rect . Left ;
15911586 _appConfig . WindowTop = rect . Top ;
15921587 _appConfig . WindowWidth = rect . Width ;
0 commit comments