Skip to content

Feature/gridview-min-max-widths #982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Mar 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
dd5cf14
Add properties MinWidth and MaxWidth to GridViewColumn
koal44 Mar 1, 2024
2ba0513
Merge branch 'development' into feature/gridview-min-max-widths
pomianowski Mar 13, 2024
e132aec
Merge branch 'fix/gridview-compatibility' into feature/gridview-min-m…
koal44 Mar 16, 2024
820752f
Merge branch 'development' into feature/gridview-min-max-widths
pomianowski Mar 19, 2024
6538c83
Merge branch 'fix/gridview-compatibility' into feature/gridview-min-m…
koal44 Mar 19, 2024
355edfb
Merge branch 'feature/gridview-min-max-widths' of https://github.com/…
koal44 Mar 19, 2024
1239911
Add documentation and move GridView related components to Wpf.Ui/Cont…
koal44 Mar 19, 2024
c2a0f87
Merge branch 'development' of https://github.com/lepoco/wpfui into pr…
pomianowski Mar 19, 2024
d6eec1c
Merge branch 'development' into feature/gridview-min-max-widths
pomianowski Mar 19, 2024
7c70b15
Greatly simplify ArrangeOverride() logic by adjusting reflected field…
koal44 Mar 19, 2024
e68dc63
Isolate ui:ListView from vanilla framework ListView completely
koal44 Mar 20, 2024
0be4416
Merge branch 'development' into feature/gridview-min-max-widths
koal44 Mar 20, 2024
d136f46
Merge branch 'feature/gridview-min-max-widths' of https://github.com/…
koal44 Mar 20, 2024
aa1e6b5
Merge branch 'development' into feature/gridview-min-max-widths
pomianowski Mar 22, 2024
5deddf0
Merge 'development' into 'feature/gridview-min-max-widths'
koal44 Mar 23, 2024
da01ce1
Add drag resizing support for GridView columns
koal44 Mar 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions src/Wpf.Ui.Gallery/Views/Pages/Collections/ListViewPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -121,31 +121,34 @@
<controls:ControlExample.XamlCode>
&lt;ListView ItemsSource=&quot;{Binding ViewModel.BasicListViewItems}&quot;&gt;\n
\t&lt;ListView.View&gt;\n
\t\t&lt;GridView&gt;\n
\t\t\t&lt;GridViewColumn DisplayMemberBinding=&quot;{Binding FirstName}&quot; Header=&quot;First Name&quot;/&gt;\n
\t\t&lt;ui:GridView&gt;\n
\t\t\t&lt;GridViewColumn DisplayMemberBinding=&quot;{Binding FirstName}&quot; Header=&quot;First Name&quot; MinWidth=&amp;quot;100&amp;quot; MaxWidth=&amp;quot;200&amp;quot;/&gt;\n
\t\t\t&lt;GridViewColumn DisplayMemberBinding=&quot;{Binding LastName}&quot; Header=&quot;Last Name&quot;/&gt;\n
\t\t\t&lt;GridViewColumn DisplayMemberBinding=&quot;{Binding Company}&quot; Header=&quot;Company&quot;/&gt;\n
\t\t&lt;/GridView&gt;\n
\t\t&lt;/ui:GridView&gt;\n
\t&lt;/ListView.View&gt;\n
&lt;/ListView&gt;
</controls:ControlExample.XamlCode>
<ui:ListView
MaxHeight="200"
d:ItemsSource="{d:SampleData ItemCount=3}"
d:ItemsSource="{d:SampleData ItemCount=2}"
BorderThickness="0"
ItemsSource="{Binding ViewModel.BasicListViewItems, Mode=TwoWay}">
<ui:ListView.View>
<GridView>
<GridViewColumn
Width="100"
<ui:GridView>
<ui:GridViewColumn
MinWidth="100"
DisplayMemberBinding="{Binding FirstName}"
Header="First Name" />
<GridViewColumn
Width="100"
<ui:GridViewColumn
MinWidth="100"
DisplayMemberBinding="{Binding LastName}"
Header="Last Name" />
<GridViewColumn DisplayMemberBinding="{Binding Company}" Header="Company" />
</GridView>
<ui:GridViewColumn
MinWidth="100"
DisplayMemberBinding="{Binding Company}"
Header="Company" />
</ui:GridView>
</ui:ListView.View>
</ui:ListView>
</controls:ControlExample>
Expand Down
2 changes: 1 addition & 1 deletion src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<system:Double x:Key="AutoSuggestBoxClearButtonHeight">24</system:Double>
<system:Double x:Key="AutoSuggestBoxClearButtonIconSize">14</system:Double>

<Style x:Key="DefaultAutoSuggestBoxItemContainerStyle" TargetType="{x:Type ListViewItem}">
<Style x:Key="DefaultAutoSuggestBoxItemContainerStyle" TargetType="{x:Type controls:ListViewItem}">
<Setter Property="Foreground" Value="{DynamicResource ListViewItemForeground}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Border.CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
Expand Down
37 changes: 37 additions & 0 deletions src/Wpf.Ui/Controls/GridView/GridView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.

namespace Wpf.Ui.Controls;

/// <summary>
/// Extends <see cref="System.Windows.Controls.GridView"/> to use Wpf.Ui custom styles
/// </summary>
/// <example>
/// To use this enhanced GridView in a ListView:
/// <code lang="xml">
/// &lt;ListView&gt;
/// &lt;ListView.View&gt;
/// &lt;local:GridView&gt;
/// &lt;GridViewColumn Header="First Name" DisplayMemberBinding="{Binding FirstName}"/&gt;
/// &lt;GridViewColumn Header="Last Name" DisplayMemberBinding="{Binding LastName}"/&gt;
/// &lt;/local:GridView&gt;
/// &lt;/ListView.View&gt;
/// &lt;/ListView&gt;
/// </code>
/// </example>
public class GridView : System.Windows.Controls.GridView
{
static GridView()
{
ResourceDictionary resourceDict = new()
{
Source = new Uri("pack://application:,,,/Wpf.Ui;component/Controls/GridView/GridViewColumnHeader.xaml")
};

Style defaultStyle = (Style)resourceDict["UiGridViewColumnHeaderStyle"];

ColumnHeaderContainerStyleProperty.OverrideMetadata(typeof(GridView), new FrameworkPropertyMetadata(defaultStyle));
}
}
118 changes: 118 additions & 0 deletions src/Wpf.Ui/Controls/GridView/GridViewColumn.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.

using System.Reflection;

namespace Wpf.Ui.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">
/// &lt;ui:ListView&gt;
/// &lt;ui:ListView.View&gt;
/// &lt;ui:GridView&gt;
/// &lt;ui:GridViewColumn
/// MinWidth="100"
/// MaxWidth="200"
/// DisplayMemberBinding="{Binding FirstName}"
/// Header="First Name" /&gt;
/// &lt;/ui:GridView&gt;
/// &lt;/ui:ListView.View&gt;
/// &lt;/ui:ListView&gt;
/// </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."));

private static FieldInfo DesiredWidthField => _desiredWidthField.Value;

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

private static MethodInfo UpdateActualWidthMethod => _updateActualWidthMethod.Value;

/// <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);
_ = UpdateActualWidthMethod.Invoke(this, null);
}

/// <summary>
/// Gets or sets the minimum width of the column.
/// </summary>
public double MinWidth
{
get => (double)GetValue(MinWidthProperty);
set => SetValue(MinWidthProperty, value);
}

/// <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 OnMinWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not GridViewColumn self)
{
return;
}

self.OnMinWidthChanged(e);
}

protected virtual void OnMinWidthChanged(DependencyPropertyChangedEventArgs e)
{
// Hook for derived classes to react to MinWidth property changes
}

/// <summary>
/// gets or sets the maximum width of the column.
/// </summary>
public double MaxWidth
{
get => (double)GetValue(MaxWidthProperty);
set => SetValue(MaxWidthProperty, value);
}

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

private static void OnMaxWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not GridViewColumn self)
{
return;
}

self.OnMaxWidthChanged(e);
}

protected virtual void OnMaxWidthChanged(DependencyPropertyChangedEventArgs e)
{
// Hook for derived classes to react to MaxWidth property changes
}
}
120 changes: 120 additions & 0 deletions src/Wpf.Ui/Controls/GridView/GridViewColumnHeader.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<!--
This Source Code Form is subject to the terms of the MIT License.
If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
Copyright (C) Leszek Pomianowski and WPF UI Contributors.
All Rights Reserved.
-->

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Wpf.Ui.Controls">

<Style x:Key="UiGridViewColumnHeaderStyle" TargetType="GridViewColumnHeader">
<Style.Triggers>
<Trigger Property="GridViewColumnHeader.Role" Value="Floating">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewColumnHeader">
<Canvas Name="PART_FloatingHeaderCanvas">
<Rectangle
Width="{TemplateBinding ActualWidth}"
Height="{TemplateBinding ActualHeight}"
Fill="#FF000000"
Opacity="0.5" />
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="GridViewColumnHeader.Role" Value="Padding">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewColumnHeader">
<Border
Name="HeaderBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
BorderThickness="0,0,0,0" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0,0,0,0" />
<Setter Property="Margin" Value="0,0,0,0" />
<Setter Property="Padding" Value="0,2" />
<Setter Property="Foreground" Value="{DynamicResource TextFillColorPrimaryBrush}" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewColumnHeader">
<Grid>
<Border
Name="HeaderBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0,0,0,0"
CornerRadius="{DynamicResource ControlCornerRadius}">
<Border Margin="6,0,0,0" Padding="{TemplateBinding Padding}">
<ContentPresenter
Name="HeaderContent"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
ContentTemplate="{TemplateBinding ContentTemplate}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<!--<TextBlock Text="{TemplateBinding Content}" />-->
</Border>
</Border>
<Canvas>
<Thumb Name="PART_HeaderGripper">
<Thumb.Style>
<Style TargetType="Thumb">
<Setter Property="Canvas.Right" Value="-9" />
<Setter Property="Width" Value="18" />
<Setter Property="Height" Value="{Binding Path=ActualHeight, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
<Setter Property="Padding" Value="0,0,0,0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Border Padding="{TemplateBinding Padding}" Background="#00FFFFFF">
<Rectangle
Width="1"
HorizontalAlignment="Center"
Fill="{TemplateBinding Background}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Thumb.Style>
</Thumb>
</Canvas>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="HeaderBorder" Property="Background" Value="{DynamicResource ListViewItemBackgroundPointerOver}" />
<Setter TargetName="PART_HeaderGripper" Property="Background" Value="Transparent" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="HeaderBorder" Property="Background" Value="Transparent" />
<Setter TargetName="PART_HeaderGripper" Property="Visibility" Value="Hidden" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

</ResourceDictionary>
26 changes: 26 additions & 0 deletions src/Wpf.Ui/Controls/GridView/GridViewHeaderRowIndicator.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!--
This Source Code Form is subject to the terms of the MIT License.
If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
Copyright (C) Leszek Pomianowski and WPF UI Contributors.
All Rights Reserved.
-->

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Wpf.Ui.Controls">

<ControlTemplate x:Key="GridViewHeaderRowIndicatorTemplate" TargetType="Separator">
<Border>
<Rectangle
Width="3"
Height="18"
Margin="0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Fill="{DynamicResource ListViewItemPillFillBrush}"
RadiusX="2"
RadiusY="2" />
</Border>
</ControlTemplate>
</ResourceDictionary>
Loading
Loading