feat: scroll to select.

This commit is contained in:
Dong Bin
2025-07-06 01:17:08 +08:00
parent 85605b5faf
commit 68f95826c5
2 changed files with 56 additions and 33 deletions

View File

@@ -46,16 +46,6 @@ public class Anchor: ItemsControl
return i;
}
internal void ScrollToAnchor(string anchorId)
{
return;
if (TargetContainer is null)
return;
var target = TargetContainer.GetVisualDescendants().FirstOrDefault(a=>Anchor.GetAnchorId(a) == anchorId);
if (target is null) return;
ScrollToAnchor(target);
}
private CancellationTokenSource _cts = new();
private bool _scrollingFromSelection = false;
@@ -109,7 +99,29 @@ public class Anchor: ItemsControl
public void InvalidatePositions()
{
InvalidateAnchorPositions();
MarkSelectedContainerByPosition();
}
private List<(string, double)> _positions = [];
internal void InvalidateAnchorPositions()
{
if (TargetContainer is null) return;
var items = TargetContainer.GetVisualDescendants().Where(a => GetAnchorId(a) is not null);
List<(string, double)> positions = new List<(string, double)>();
foreach (var item in items)
{
var anchorId = GetAnchorId(item);
if (anchorId is null) continue;
var position = item.TransformToVisual(TargetContainer)?.M32;
if (position.HasValue)
{
positions.Add((anchorId, position.Value));
}
}
positions.Sort((a, b) => a.Item2.CompareTo(b.Item2));
_positions = positions;
}
protected override void OnLoaded(RoutedEventArgs e)
@@ -122,12 +134,22 @@ public class Anchor: ItemsControl
var tops = targetItems.Select(a => (a.TransformToVisual(target)?.M32, GetAnchorId(a)));
var isloaded = TargetContainer?.IsLoaded;
TargetContainer?.AddHandler(ScrollViewer.ScrollChangedEvent, OnScrollChanged);
if (isloaded is true)
{
InvalidateAnchorPositions();
}
else
{
TargetContainer.Loaded += (s, args) => InvalidateAnchorPositions();
}
MarkSelectedContainerByPosition();
}
private void OnScrollChanged(object? sender, ScrollChangedEventArgs e)
{
if (_scrollingFromSelection) return;
Debug.WriteLine("Scroll changed");
MarkSelectedContainerByPosition();
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
@@ -135,12 +157,7 @@ public class Anchor: ItemsControl
base.OnPointerPressed(e);
var source = (e.Source as Visual).GetContainerFromEventSource<AnchorItem>();
if (source is null) return;
if (_selectedContainer is not null)
{
_selectedContainer.IsSelected = false;
}
source.IsSelected = true;
_selectedContainer = source;
MarkSelectedContainer(source);
var target = TargetContainer?.GetVisualDescendants()
.FirstOrDefault(a => Anchor.GetAnchorId(a) == source?.AnchorId);
if (target is null) return;
@@ -172,5 +189,26 @@ public class Anchor: ItemsControl
internal AnchorItem? _selectedContainer;
internal void MarkSelectedContainer(AnchorItem? item)
{
var oldValue = _selectedContainer;
var newValue = item;
if (oldValue == newValue) return;
_selectedContainer?.SetValue(AnchorItem.IsSelectedProperty, false);
_selectedContainer = newValue;
_selectedContainer?.SetValue(AnchorItem.IsSelectedProperty, true);
}
internal void MarkSelectedContainerByPosition()
{
if (TargetContainer is null) return;
var top = TargetContainer.Offset.Y;
var topAnchorId = _positions.LastOrDefault(a => a.Item2 <= top).Item1;
if (topAnchorId is null) return;
var item = this.GetVisualDescendants().OfType<AnchorItem>()
.FirstOrDefault(a => a.AnchorId == topAnchorId);
if (item is null) return;
MarkSelectedContainer(item);
}
}

View File

@@ -55,21 +55,6 @@ public class AnchorItem : HeaderedItemsControl, ISelectable
}
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
// var item = new TreeViewItem();
base.OnPointerPressed(e);
return;
if (e.Handled) return;
if (_root is null)
return;
if (!string.IsNullOrEmpty(AnchorId))
{
_root.ScrollToAnchor(AnchorId);
e.Handled = true;
}
}
protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
{
return EnsureRoot().CreateContainerForItemOverride_INTERNAL(item, index, recycleKey);