2025-02-10 20:53:40 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
|
|
namespace WPFluent.Controls;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Extends <see cref="System.Windows.Controls.GridViewColumn"/> with MinWidth and MaxWidth properties. It can be used
|
|
|
|
|
|
/// with <see cref="ListView"/> when in GridView mode.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <example>
|
|
|
|
|
|
/// <code lang="xml"> /// <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> ///</code>
|
|
|
|
|
|
/// </example>
|
|
|
|
|
|
public class GridViewColumn : System.Windows.Controls.GridViewColumn
|
|
|
|
|
|
{
|
|
|
|
|
|
// use reflection to get the `_desiredWidth` private field.
|
|
|
|
|
|
private static readonly Lazy<FieldInfo> _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<MethodInfo> _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;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Identifies the <see cref="MaxWidth"/> dependency property.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static readonly DependencyProperty MaxWidthProperty = DependencyProperty.Register(
|
|
|
|
|
|
nameof(MaxWidth),
|
|
|
|
|
|
typeof(double),
|
|
|
|
|
|
typeof(GridViewColumn),
|
|
|
|
|
|
new FrameworkPropertyMetadata(double.PositiveInfinity, OnMaxWidthChanged));
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Identifies the <see cref="MinWidth"/> dependency property.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Updates the desired width of the column to be clamped between MinWidth and MaxWidth).
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>
|
|
|
|
|
|
/// Uses reflection to directly set the private `_desiredWidth` field on the
|
|
|
|
|
|
/// `System.Windows.Controls.GridViewColumn`.
|
|
|
|
|
|
/// </remarks>
|
|
|
|
|
|
/// <exception cref="InvalidOperationException">
|
|
|
|
|
|
/// Thrown if reflection fails to access the `_desiredWidth` field
|
|
|
|
|
|
/// </exception>
|
|
|
|
|
|
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);
|
2025-04-24 20:56:44 +08:00
|
|
|
|
UpdateActualWidthMethod.Invoke(this, null);
|
2025-02-10 20:53:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// gets or sets the maximum width of the column.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public double MaxWidth { get => (double)GetValue(MaxWidthProperty); set => SetValue(MaxWidthProperty, value); }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Gets or sets the minimum width of the column.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public double MinWidth { get => (double)GetValue(MinWidthProperty); set => SetValue(MinWidthProperty, value); }
|
|
|
|
|
|
}
|