using System.Reflection; namespace WPFluent.Controls; /// /// Extends with MinWidth and MaxWidth properties. It can be used /// with when in GridView mode. /// /// /// /// <ui:ListView> /// <ui:ListView.View> /// <ui:GridView> /// /// <ui:GridViewColumn /// MinWidth="100" /// MaxWidth="200" /// /// DisplayMemberBinding="{Binding FirstName}" /// Header="First Name" /> /// /// </ui:GridView> /// </ui:ListView.View> /// </ui:ListView> /// /// public class GridViewColumn : System.Windows.Controls.GridViewColumn { // use reflection to get the `_desiredWidth` private field. private static readonly Lazy _desiredWidthField = new( () => typeof(System.Windows.Controls.GridViewColumn).GetField( "_desiredWidth", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException("The `_desiredWidth` field was not found.")); // use reflection to get the `UpdateActualWidth` private method. private static readonly Lazy _updateActualWidthMethod = new( () => { MethodInfo methodInfo = typeof(System.Windows.Controls.GridViewColumn).GetMethod( "UpdateActualWidth", BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new InvalidOperationException("The `UpdateActualWidth` method was not found."); return methodInfo; }); /// /// Identifies the dependency property. /// public static readonly DependencyProperty MaxWidthProperty = DependencyProperty.Register( nameof(MaxWidth), typeof(double), typeof(GridViewColumn), new FrameworkPropertyMetadata(double.PositiveInfinity, OnMaxWidthChanged)); /// /// Identifies the dependency property. /// public static readonly DependencyProperty MinWidthProperty = DependencyProperty.Register( nameof(MinWidth), typeof(double), typeof(GridViewColumn), new FrameworkPropertyMetadata(0.0, OnMinWidthChanged)); private static void OnMaxWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if(d is not GridViewColumn self) { return; } self.OnMaxWidthChanged(e); } private static void OnMinWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if(d is not GridViewColumn self) { return; } self.OnMinWidthChanged(e); } private static FieldInfo DesiredWidthField => _desiredWidthField.Value; private static MethodInfo UpdateActualWidthMethod => _updateActualWidthMethod.Value; protected virtual void OnMaxWidthChanged(DependencyPropertyChangedEventArgs e) { // Hook for derived classes to react to MaxWidth property changes } protected virtual void OnMinWidthChanged(DependencyPropertyChangedEventArgs e) { // Hook for derived classes to react to MinWidth property changes } /// /// Updates the desired width of the column to be clamped between MinWidth and MaxWidth). /// /// /// Uses reflection to directly set the private `_desiredWidth` field on the /// `System.Windows.Controls.GridViewColumn`. /// /// /// Thrown if reflection fails to access the `_desiredWidth` field /// internal void UpdateDesiredWidth() { double currentWidth = (double)(DesiredWidthField.GetValue(this) ?? throw new InvalidOperationException("Failed to get the current `_desiredWidth`.")); double clampedWidth = Math.Max(MinWidth, Math.Min(currentWidth, MaxWidth)); DesiredWidthField.SetValue(this, clampedWidth); UpdateActualWidthMethod.Invoke(this, null); } /// /// gets or sets the maximum width of the column. /// public double MaxWidth { get => (double)GetValue(MaxWidthProperty); set => SetValue(MaxWidthProperty, value); } /// /// Gets or sets the minimum width of the column. /// public double MinWidth { get => (double)GetValue(MinWidthProperty); set => SetValue(MinWidthProperty, value); } }