Skip to content

Commit 3367439

Browse files
authored
Merge pull request #338 from w-ahmad/fix/row-details-state
fix: persist row details pane state per-item
2 parents 2a7e8ac + 696eda7 commit 3367439

File tree

5 files changed

+64
-15
lines changed

5 files changed

+64
-15
lines changed

src/Helpers/TValue.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace WinUI.TableView.Helpers;
2+
3+
/// <summary>
4+
/// Represents a value type wrapper that enables implicit conversion between the wrapped value and the wrapper type.
5+
/// </summary>
6+
/// <typeparam name="T">The value type to be wrapped. Must be a struct.</typeparam>
7+
/// <param name="Value">The value to wrap.</param>
8+
internal record TValue<T>(T Value) where T : struct
9+
{
10+
/// <summary>
11+
/// Defines an implicit conversion from a <see cref="TValue{T}"/> instance to its underlying value of type T.
12+
/// </summary>
13+
public static implicit operator T(TValue<T> value)
14+
{
15+
return value.Value;
16+
}
17+
18+
/// <summary>
19+
/// Defines an implicit conversion from the underlying value type to a <see cref="TValue{T}"/> instance.
20+
/// </summary>
21+
public static implicit operator TValue<T>(T value)
22+
{
23+
return new(value);
24+
}
25+
}

src/TableView.Properties.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
using System;
77
using System.Collections.Generic;
88
using System.Linq;
9+
using System.Runtime.CompilerServices;
910
using System.Threading.Tasks;
11+
using WinUI.TableView.Helpers;
1012

1113
namespace WinUI.TableView;
1214

@@ -262,7 +264,7 @@ public partial class TableView
262264
/// <summary>
263265
/// Identifies the <see cref="ShowFilterItemsCount"/> dependency property.
264266
/// </summary>
265-
public static readonly DependencyProperty ShowFilterItemsCountProperty = DependencyProperty.Register(nameof(ShowFilterItemsCount), typeof(bool), typeof(TableView), new PropertyMetadata(false));
267+
public static readonly DependencyProperty ShowFilterItemsCountProperty = DependencyProperty.Register(nameof(ShowFilterItemsCount), typeof(bool), typeof(TableView), new PropertyMetadata(false));
266268

267269
/// <summary>
268270
/// Gets or sets a value indicating whether opening the column filter over header right-click is enabled.
@@ -359,6 +361,11 @@ public bool ShowFilterItemsCount
359361
/// </summary>
360362
internal bool IsEditing { get; private set; }
361363

364+
/// <summary>
365+
/// Gets the visibility states of details pane for each item.
366+
/// </summary>
367+
internal ConditionalWeakTable<object, TValue<bool>> DetailsPaneStates { get; } = [];
368+
362369
/// <summary>
363370
/// Gets or sets the filter handler for the TableView.
364371
/// </summary>

src/TableView.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ protected override void PrepareContainerForItemOverride(DependencyObject element
109109
{
110110
row.EnsureCellsStyle(default, item);
111111
row.ApplyCellsSelectionState();
112+
row.RowPresenter?.ApplyDetailsPaneState(item);
112113

113114
if (CurrentCellSlot.HasValue)
114115
{
@@ -675,6 +676,8 @@ private static TableViewBoundColumn GetTableViewColumnFromType(string? propertyN
675676
/// </summary>
676677
private void ItemsSourceChanged(DependencyPropertyChangedEventArgs e)
677678
{
679+
DetailsPaneStates.Clear();
680+
678681
using var defer = _collectionView.DeferRefresh();
679682
_collectionView.Source = null!;
680683

src/TableViewRowPresenter.cs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.UI.Xaml.Controls;
44
using Microsoft.UI.Xaml.Controls.Primitives;
55
using Microsoft.UI.Xaml.Data;
6+
using Microsoft.UI.Xaml.Input;
67
using Microsoft.UI.Xaml.Media;
78
using Microsoft.UI.Xaml.Shapes;
89
using System;
@@ -68,8 +69,7 @@ protected override void OnApplyTemplate()
6869

6970
if (_detailsToggleButton is not null)
7071
{
71-
_detailsToggleButton.Checked += OnDetailsToggleButtonChecked;
72-
_detailsToggleButton.Unchecked += OnDetailsToggleButtonUnChecked;
72+
_detailsToggleButton.Tapped += OnDetailsToggleButtonTapped;
7373
}
7474

7575
if (_detailsPanel is not null)
@@ -190,11 +190,8 @@ internal void SetRowDetailsVisibility()
190190
}
191191
else if (mode is TableViewRowDetailsVisibilityMode.VisibleWhenSelected)
192192
{
193-
if (_detailsToggleButton is not null)
194-
_detailsToggleButton.IsChecked = TableViewRow?.IsSelected ?? false;
195-
else
196-
VisualStates.GoToState(this, false, (TableViewRow?.IsSelected ?? false) ? VisualStates.StateDetailsVisible : VisualStates.StateDetailsCollapsed);
197-
193+
var state = (TableViewRow?.IsSelected ?? false) ? VisualStates.StateDetailsVisible : VisualStates.StateDetailsCollapsed;
194+
VisualStates.GoToState(this, false, state);
198195
VisualStates.GoToState(this, false, VisualStates.StateDetailsButtonCollapsed);
199196
}
200197
else if (mode is TableViewRowDetailsVisibilityMode.VisibleWhenExpanded)
@@ -209,19 +206,37 @@ internal void SetRowDetailsVisibility()
209206
}
210207

211208
/// <summary>
212-
/// Handles the Checked event of the details toggle button.
209+
/// Handles the Tapped event of the details toggle button.
210+
/// </summary>
211+
private void OnDetailsToggleButtonTapped(object sender, TappedRoutedEventArgs e)
212+
{
213+
ToggleDetailsPane(TableViewRow?.Content, _detailsToggleButton!.IsChecked ?? false);
214+
}
215+
216+
/// <summary>
217+
/// Toggles the visibility of the details pane.
213218
/// </summary>
214-
private void OnDetailsToggleButtonChecked(object sender, RoutedEventArgs e)
219+
private void ToggleDetailsPane(object? content, bool isVisible)
215220
{
216-
VisualStates.GoToState(this, false, VisualStates.StateDetailsVisible);
221+
if (TableView is null || content is null) return;
222+
223+
TableView.DetailsPaneStates.AddOrUpdate(content, isVisible);
224+
var state = isVisible ? VisualStates.StateDetailsVisible : VisualStates.StateDetailsCollapsed;
225+
VisualStates.GoToState(this, false, state);
217226
}
218227

219228
/// <summary>
220-
/// Handles the Unchecked event of the details toggle button.
229+
/// Ensures that the details pane visibility is synchronized for the specified item when row.
221230
/// </summary>
222-
private void OnDetailsToggleButtonUnChecked(object sender, RoutedEventArgs e)
231+
internal void ApplyDetailsPaneState(object? item)
223232
{
224-
VisualStates.GoToState(this, false, VisualStates.StateDetailsCollapsed);
233+
if (TableView?.RowDetailsVisibilityMode is TableViewRowDetailsVisibilityMode.VisibleWhenExpanded &&
234+
_detailsToggleButton is not null && TableView is not null && item is not null)
235+
{
236+
var isChecked = TableView.DetailsPaneStates.TryGetValue(item, out var value) ? value.Value : false;
237+
_detailsToggleButton!.IsChecked = isChecked;
238+
ToggleDetailsPane(item, isChecked);
239+
}
225240
}
226241

227242
/// <summary>

src/Themes/TableViewRowPresenter.xaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,6 @@
131131

132132
<ContentPresenter x:Name="DetailsPresenter"
133133
Grid.Row="1"
134-
Content="{Binding}"
135134
Padding="{ThemeResource TableViewDetailsPadding}" />
136135
</Grid>
137136
</Grid>

0 commit comments

Comments
 (0)