Skip to content

Commit 96bc3ef

Browse files
committed
fixed row and cell selection on Uno platform
1 parent b41522b commit 96bc3ef

File tree

8 files changed

+218
-79
lines changed

8 files changed

+218
-79
lines changed

src/Extensions/ItemIndexRangeExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,15 @@ public static bool IsInRange(this ItemIndexRange range, int index)
1717
{
1818
return index >= range.FirstIndex && index <= range.LastIndex;
1919
}
20+
21+
/// <summary>
22+
/// Determines whether the given item index range is valid within the TableView.
23+
/// </summary>
24+
/// <param name="itemIndexRange">The ItemIndexRange to check.</param>
25+
/// <param name="tableView">The TableView to check against.</param>
26+
/// <returns>True if the item index range of TableView is valid; otherwise, false.</returns>
27+
public static bool IsValid(this ItemIndexRange itemIndexRange, TableView tableView)
28+
{
29+
return itemIndexRange.FirstIndex >= 0 && itemIndexRange.LastIndex < tableView?.Items.Count;
30+
}
2031
}

src/TableView.cs

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,7 @@ private void TableView_SelectionChanged(object sender, SelectionChangedEventArgs
7070
{
7171
SelectedCellRanges.RemoveWhere(slots =>
7272
{
73-
#if WINDOWS
7473
slots.RemoveWhere(slot => SelectedRanges.Any(range => range.IsInRange(slot.Row)));
75-
#endif
7674
return slots.Count == 0;
7775
});
7876
}
@@ -360,14 +358,12 @@ public string GetSelectedContent(bool includeHeaders, char separator = '\t')
360358

361359
if (SelectedItems.Any() || SelectedCells.Count != 0)
362360
{
363-
#if WINDOWS
364361
slots = SelectedRanges.SelectMany(x => Enumerable.Range(x.FirstIndex, (int)x.Length))
365-
.SelectMany(r => Enumerable.Range(0, Columns.VisibleColumns.Count)
366-
.Select(c => new TableViewCellSlot(r, c)))
367-
.Concat(SelectedCells)
368-
.OrderBy(x => x.Row)
369-
.ThenByDescending(x => x.Column);
370-
#endif
362+
.SelectMany(r => Enumerable.Range(0, Columns.VisibleColumns.Count)
363+
.Select(c => new TableViewCellSlot(r, c)))
364+
.Concat(SelectedCells)
365+
.OrderBy(x => x.Row)
366+
.ThenByDescending(x => x.Column);
371367
}
372368
else if (CurrentCellSlot.HasValue)
373369
{
@@ -813,9 +809,7 @@ public void RefreshFilter()
813809
break;
814810
case ListViewSelectionMode.Multiple:
815811
case ListViewSelectionMode.Extended:
816-
#if WINDOWS
817812
SelectRange(new ItemIndexRange(0, (uint)Items.Count));
818-
#endif
819813
break;
820814
}
821815
}
@@ -875,9 +869,7 @@ private void DeselectAllItems()
875869
break;
876870
case ListViewSelectionMode.Multiple:
877871
case ListViewSelectionMode.Extended:
878-
#if WINDOWS
879872
DeselectRange(new ItemIndexRange(0, (uint)Items.Count));
880-
#endif
881873
break;
882874
}
883875
}
@@ -925,9 +917,9 @@ internal void MakeSelection(TableViewCellSlot slot, bool shiftKey, bool ctrlKey
925917
{
926918
SelectRows(slot, shiftKey);
927919
LastSelectionUnit = TableViewSelectionUnit.Row;
928-
}
929-
else
930-
{
920+
}
921+
else
922+
{
931923
SelectCells(slot, shiftKey);
932924
LastSelectionUnit = TableViewSelectionUnit.Cell;
933925
}
@@ -944,22 +936,21 @@ internal void MakeSelection(TableViewCellSlot slot, bool shiftKey, bool ctrlKey
944936
/// </summary>
945937
private void SelectRows(TableViewCellSlot slot, bool shiftKey)
946938
{
947-
#if WINDOWS
948939
var selectionRange = SelectedRanges.FirstOrDefault(x => x.IsInRange(slot.Row));
949940
SelectionStartRowIndex ??= slot.Row;
950941
CurrentRowIndex = slot.Row;
951942

952943
if (selectionRange is not null)
953944
{
954945
DeselectRange(selectionRange);
955-
}
946+
}
956947

957948
if (shiftKey && SelectionMode is ListViewSelectionMode.Multiple or ListViewSelectionMode.Extended)
958949
{
959950
var min = Math.Min(SelectionStartRowIndex.Value, slot.Row);
960951
var max = Math.Max(SelectionStartRowIndex.Value, slot.Row);
961952

962-
SelectRange(new ItemIndexRange(min, (uint)(max - min) + 1));
953+
SelectRange(new ItemIndexRange(min, (uint)(max - min) + 1));
963954
}
964955
else
965956
{
@@ -972,7 +963,7 @@ private void SelectRows(TableViewCellSlot slot, bool shiftKey)
972963
{
973964
SelectRange(new ItemIndexRange(slot.Row, 1));
974965
}
975-
}
966+
}
976967

977968
if (!IsReadOnly && slot.IsValid(this))
978969
{
@@ -986,7 +977,6 @@ private void SelectRows(TableViewCellSlot slot, bool shiftKey)
986977
row?.Focus(FocusState.Programmatic);
987978
});
988979
}
989-
#endif
990980
}
991981

992982
/// <summary>

src/TableViewCell.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,17 @@ protected override void OnManipulationDelta(ManipulationDeltaRoutedEventArgs e)
236236

237237
if (_scrollViewer is { })
238238
{
239+
#if WINDOWS
239240
var transform = _scrollViewer.TransformToVisual(this).Inverse;
240241
var point = transform.TransformPoint(position);
241242
var transformedPoint = _scrollViewer.TransformToVisual(null).TransformPoint(point);
242243
return VisualTreeHelper.FindElementsInHostCoordinates(transformedPoint, _scrollViewer)
244+
#else
245+
return VisualTreeHelper.FindElementsInHostCoordinates(position, _scrollViewer, true)
246+
.OfType<ContentPresenter>()
247+
.Where(x => x.Name is "Content")
248+
.Select(x => x.FindAscendant<TableViewCell>() is { } cell ? cell : default)
249+
#endif
243250
.OfType<TableViewCell>()
244251
.FirstOrDefault();
245252
}

src/TableViewHeaderRow.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,14 +362,11 @@ internal void SetCornerButtonState()
362362
{
363363
var stateName = VisualStates.StateNoButton;
364364

365-
#if WINDOWS
366365
if (TableView is ListView { SelectionMode: ListViewSelectionMode.Multiple })
367366
{
368367
stateName = TableView.IsEditing ? VisualStates.StateSelectAllCheckBoxDisabled : VisualStates.StateSelectAllCheckBox;
369368
}
370-
else
371-
#endif
372-
if (TableView is { CornerButtonMode: TableViewCornerButtonMode.Options })
369+
else if (TableView is { CornerButtonMode: TableViewCornerButtonMode.Options })
373370
{
374371
stateName = TableView.IsEditing ? VisualStates.StateOptionsButtonDisabled : VisualStates.StateOptionsButton;
375372
}

src/TableViewRow.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,14 +500,26 @@ internal void EnsureGridLines()
500500
/// </summary>
501501
internal void EnsureLayout()
502502
{
503-
#if WINDOWS
504503
if (CellPresenter is not null && TableView is not null)
505504
{
506505
CellPresenter.Padding = ((ListView)TableView).SelectionMode is ListViewSelectionMode.Multiple
506+
#if WINDOWS
507507
? new Thickness(16, 0, 16, 0)
508+
#else
509+
? new Thickness(8, 0, 16, 0)
510+
#endif
508511
: new Thickness(20, 0, 16, 0);
509-
}
512+
#if !WINDOWS
513+
var multiSelectSquare = this.FindDescendant<Border>(x => x.Name is "MultiSelectSquare");
514+
if (multiSelectSquare is not null)
515+
{
516+
multiSelectSquare.Opacity = 0.5;
517+
multiSelectSquare.CornerRadius = new CornerRadius(4);
518+
multiSelectSquare.BorderThickness = new Thickness(1);
519+
multiSelectSquare.Margin = new Thickness(10, 0, 0, 0);
520+
}
510521
#endif
522+
}
511523
}
512524

513525
/// <summary>

src/Tableview.Uno.cs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#if !WINDOWS
2+
using Microsoft.UI.Xaml.Controls.Primitives;
3+
using Microsoft.UI.Xaml.Data;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Reflection;
8+
using WinUI.TableView.Extensions;
9+
10+
namespace WinUI.TableView;
11+
12+
/// <summary>
13+
/// Partial class for TableView that contains Uno stuff.
14+
/// </summary>
15+
partial class TableView
16+
{
17+
private const BindingFlags BindingAttr = BindingFlags.NonPublic | BindingFlags.Instance;
18+
private PropertyInfo? _disableRaiseSelectionChangedPropertyInfo;
19+
private MethodInfo? _invokeSelectionChangedMethodInfo;
20+
21+
private void SetDisableRaiseSelectionChanged(bool value)
22+
{
23+
_disableRaiseSelectionChangedPropertyInfo ??= typeof(Selector).GetProperty("DisableRaiseSelectionChanged", BindingAttr);
24+
_disableRaiseSelectionChangedPropertyInfo?.SetValue(this, value);
25+
}
26+
27+
private void InvokeSelectionChanged(object[] removedItems, object[] addedItems)
28+
{
29+
_invokeSelectionChangedMethodInfo ??= typeof(Selector).GetMethod("InvokeSelectionChanged", BindingAttr);
30+
_invokeSelectionChangedMethodInfo?.Invoke(this, [removedItems, addedItems]);
31+
}
32+
33+
private new void DeselectRange(ItemIndexRange itemIndexRange)
34+
{
35+
var removedItems = new List<object>();
36+
37+
SetDisableRaiseSelectionChanged(true);
38+
{
39+
if (!itemIndexRange.IsValid(this))
40+
{
41+
throw new IndexOutOfRangeException("The given item index range bounds are not valid.");
42+
}
43+
44+
for (var index = itemIndexRange.FirstIndex; index <= itemIndexRange.LastIndex; index++)
45+
{
46+
var item = Items[index];
47+
if (SelectedItems.Contains(item))
48+
{
49+
removedItems.Add(item);
50+
SelectedItems.Remove(item);
51+
}
52+
}
53+
54+
AdjustSelectedRanges();
55+
}
56+
SetDisableRaiseSelectionChanged(false);
57+
58+
InvokeSelectionChanged([.. removedItems], []);
59+
}
60+
61+
private void AdjustSelectedRanges()
62+
{
63+
SelectedRanges.Clear();
64+
65+
if (SelectedItems.Count == 0) return;
66+
67+
var selectedIndexes = SelectedItems.Select(Items.IndexOf).Order();
68+
var start = selectedIndexes.First();
69+
var prev = start;
70+
71+
foreach (var index in selectedIndexes)
72+
{
73+
if (index != prev + 1)
74+
{
75+
var length = (uint)(prev - start + 1);
76+
SelectedRanges.Add(new ItemIndexRange(start, length));
77+
start = index;
78+
}
79+
prev = index;
80+
}
81+
82+
var finalLength = (uint)(prev - start + 1);
83+
SelectedRanges.Add(new ItemIndexRange(start, finalLength));
84+
}
85+
86+
private new void SelectRange(ItemIndexRange itemIndexRange)
87+
{
88+
var addedItems = new List<object>();
89+
90+
SetDisableRaiseSelectionChanged(true);
91+
{
92+
if (!itemIndexRange.IsValid(this))
93+
{
94+
throw new IndexOutOfRangeException("The given item index range bounds are not valid.");
95+
}
96+
97+
for (var index = itemIndexRange.FirstIndex; index <= itemIndexRange.LastIndex; index++)
98+
{
99+
var item = Items[index];
100+
if (!SelectedItems.Contains(item))
101+
{
102+
addedItems.Add(item);
103+
SelectedItems.Add(item);
104+
}
105+
}
106+
107+
AdjustSelectedRanges();
108+
}
109+
SetDisableRaiseSelectionChanged(false);
110+
111+
InvokeSelectionChanged([], [.. addedItems]);
112+
}
113+
114+
private new IList<ItemIndexRange> SelectedRanges { get; } = [];
115+
}
116+
#endif

src/Themes/TableViewCellsPresenter.xaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@
3434

3535
<Rectangle x:Name="VerticalGridLine"
3636
Width="1"
37-
VerticalAlignment="Stretch" />
37+
VerticalAlignment="Stretch"
38+
IsHitTestVisible="False" />
3839
</Grid>
3940

4041
<Rectangle x:Name="HorizontalGridLine"
4142
Grid.Row="1"
4243
Margin="-24,0,0,0"
43-
HorizontalAlignment="Stretch" />
44+
HorizontalAlignment="Stretch"
45+
IsHitTestVisible="False" />
4446
</Grid>
4547
</ControlTemplate>
4648
</Setter.Value>

0 commit comments

Comments
 (0)