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); }
}