@@ -13,84 +13,55 @@ namespace NETworkManager.Utilities.WPF;
1313/// </summary>
1414public static class DataGridHelper
1515{
16- /// <summary>
17- /// When set to <see langword="true"/>, forces star-sized columns to recompute their width after
18- /// the first row is realized. Without this, an initially empty <see cref="DataGrid"/> sizes star
19- /// columns to <c>MinWidth</c> because the inner <see cref="System.Windows.Controls.ScrollViewer"/>
20- /// measures with infinite width; only a window resize would otherwise trigger a correct re-measure.
21- /// The handler unsubscribes itself after the first row so there is no ongoing overhead.
22- /// </summary>
23- public static readonly DependencyProperty RefreshStarColumnsOnFirstRowProperty =
24- DependencyProperty . RegisterAttached (
25- "RefreshStarColumnsOnFirstRow" ,
26- typeof ( bool ) ,
27- typeof ( DataGridHelper ) ,
28- new PropertyMetadata ( false , OnRefreshStarColumnsOnFirstRowChanged ) ) ;
29-
30- public static void SetRefreshStarColumnsOnFirstRow ( DataGrid element , bool value ) =>
31- element . SetValue ( RefreshStarColumnsOnFirstRowProperty , value ) ;
32-
33- public static bool GetRefreshStarColumnsOnFirstRow ( DataGrid element ) =>
34- ( bool ) element . GetValue ( RefreshStarColumnsOnFirstRowProperty ) ;
35-
36- private static void OnRefreshStarColumnsOnFirstRowChanged ( DependencyObject d ,
37- DependencyPropertyChangedEventArgs e )
38- {
39- if ( d is not DataGrid dataGrid || e . NewValue is not bool enabled || ! enabled )
40- return ;
41-
42- dataGrid . LoadingRow += Handler ;
43- return ;
44-
45- void Handler ( object sender , DataGridRowEventArgs args )
46- {
47- dataGrid . LoadingRow -= Handler ;
48-
49- dataGrid . Dispatcher . BeginInvoke ( new Action ( ( ) =>
50- {
51- foreach ( var column in dataGrid . Columns )
52- {
53- if ( ! column . Width . IsStar )
54- continue ;
55-
56- var width = column . Width ;
57- column . Width = 0 ;
58- column . Width = width ;
59- }
60- } ) , DispatcherPriority . ContextIdle ) ;
61- }
62- }
63-
64- #region FillLastColumn
16+ #region FillRemainingWidth
6517
6618 /// <summary>
67- /// When set to <see langword="true"/>, the last visible column fills the remaining width of the
68- /// <see cref="DataGrid"/> - like a star (<c>*</c>) column, but with a pixel width. With a visible star column the
19+ /// When set to <see langword="true"/>, a column fills the remaining width of the <see cref="DataGrid"/> - like a
20+ /// star (<c>*</c>) column, but with a pixel width: the visible column marked with <see cref="IsFillColumnProperty"/>,
21+ /// otherwise the last visible column. With a visible star column the
6922 /// DataGrid only lets a column grow by taking the width from the columns to its right (down to their
7023 /// <c>MinWidth</c>), so a column can't be resized wider than the grid (also not with a double-click on the
7124 /// gripper), there is never a horizontal scrollbar (#3557). Without star columns a column grows freely and the
7225 /// grid scrolls horizontally.
7326 /// <para>
7427 /// The fill column gets max(base width, available width - other visible columns). The base width is its
7528 /// <c>MinWidth</c>, or the width the user resized it to. It is updated when the size of the grid / its viewport
76- /// changes and when another column is resized or shown / hidden. A column that is no longer the last visible one
29+ /// changes and when another column is resized or shown / hidden. A column that no longer fills (e.g. hidden)
7730 /// gets its original width back. Don't use star columns in the same grid.
7831 /// </para>
7932 /// </summary>
80- public static readonly DependencyProperty FillLastColumnProperty =
33+ public static readonly DependencyProperty FillRemainingWidthProperty =
8134 DependencyProperty . RegisterAttached (
82- "FillLastColumn " ,
35+ "FillRemainingWidth " ,
8336 typeof ( bool ) ,
8437 typeof ( DataGridHelper ) ,
85- new PropertyMetadata ( false , OnFillLastColumnChanged ) ) ;
38+ new PropertyMetadata ( false , OnFillRemainingWidthChanged ) ) ;
8639
87- public static void SetFillLastColumn ( DataGrid element , bool value ) =>
88- element . SetValue ( FillLastColumnProperty , value ) ;
40+ public static void SetFillRemainingWidth ( DataGrid element , bool value ) =>
41+ element . SetValue ( FillRemainingWidthProperty , value ) ;
8942
90- public static bool GetFillLastColumn ( DataGrid element ) =>
91- ( bool ) element . GetValue ( FillLastColumnProperty ) ;
43+ public static bool GetFillRemainingWidth ( DataGrid element ) =>
44+ ( bool ) element . GetValue ( FillRemainingWidthProperty ) ;
9245
93- // State of a grid with FillLastColumn (subscriptions, current fill column)
46+ /// <summary>
47+ /// Marks the column that fills the remaining width (see <see cref="FillRemainingWidthProperty"/>), if it isn't the
48+ /// last column (e.g. a description in the middle of the columns). While it is hidden, the last visible column
49+ /// fills.
50+ /// </summary>
51+ public static readonly DependencyProperty IsFillColumnProperty =
52+ DependencyProperty . RegisterAttached (
53+ "IsFillColumn" ,
54+ typeof ( bool ) ,
55+ typeof ( DataGridHelper ) ,
56+ new PropertyMetadata ( false ) ) ;
57+
58+ public static void SetIsFillColumn ( DataGridColumn element , bool value ) =>
59+ element . SetValue ( IsFillColumnProperty , value ) ;
60+
61+ public static bool GetIsFillColumn ( DataGridColumn element ) =>
62+ ( bool ) element . GetValue ( IsFillColumnProperty ) ;
63+
64+ // State of a grid with FillRemainingWidth (subscriptions, current fill column)
9465 private static readonly DependencyProperty FillStateProperty =
9566 DependencyProperty . RegisterAttached (
9667 "FillState" ,
@@ -104,7 +75,7 @@ public static bool GetFillLastColumn(DataGrid element) =>
10475 private static readonly DependencyPropertyDescriptor ColumnVisibilityDescriptor =
10576 DependencyPropertyDescriptor . FromProperty ( DataGridColumn . VisibilityProperty , typeof ( DataGridColumn ) ) ;
10677
107- private static void OnFillLastColumnChanged ( DependencyObject d , DependencyPropertyChangedEventArgs e )
78+ private static void OnFillRemainingWidthChanged ( DependencyObject d , DependencyPropertyChangedEventArgs e )
10879 {
10980 if ( d is not DataGrid dataGrid )
11081 return ;
@@ -239,22 +210,25 @@ private void Update()
239210 if ( ! dataGrid . IsLoaded )
240211 return ;
241212
242- var lastVisibleColumn = dataGrid . Columns
213+ var visibleColumns = dataGrid . Columns
243214 . Where ( x => x . Visibility == Visibility . Visible )
244215 . OrderBy ( x => x . DisplayIndex )
245- . LastOrDefault ( ) ;
216+ . ToList ( ) ;
217+
218+ // Marked fill column, otherwise the last visible column
219+ var fillColumn = visibleColumns . FirstOrDefault ( GetIsFillColumn ) ?? visibleColumns . LastOrDefault ( ) ;
246220
247221 _isUpdating = true ;
248222
249223 try
250224 {
251- if ( ! ReferenceEquals ( lastVisibleColumn , _fillColumn ) )
225+ if ( ! ReferenceEquals ( fillColumn , _fillColumn ) )
252226 {
253227 // Give the previous fill column its original width back
254228 if ( _fillColumn != null && dataGrid . Columns . Contains ( _fillColumn ) )
255229 _fillColumn . Width = _fillColumnOriginalWidth ;
256230
257- _fillColumn = lastVisibleColumn ;
231+ _fillColumn = fillColumn ;
258232 _lastSetWidth = double . NaN ;
259233
260234 if ( _fillColumn == null )
0 commit comments