Skip to content
Draft
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace iNKORE.UI.WPF.Modern.Controls
{
Expand Down Expand Up @@ -27,6 +28,76 @@ protected override void OnChildDesiredSizeChanged(UIElement child)
}
}

// Default alignment for BringIntoView: 0.0 means align to top/left edge of viewport
private const double DefaultBringIntoViewAlignment = 0.0;

// Default offset for BringIntoView: no additional offset
private const double DefaultBringIntoViewOffset = 0.0;

// Default animation for BringIntoView: false for immediate scrolling
private const bool DefaultBringIntoViewAnimate = false;

protected override void OnRequestBringIntoView(RequestBringIntoViewEventArgs e)
{
// Forward the BringIntoView request to the ItemsRepeaterScrollHost if one exists.
// This enables BringIntoView to work properly with virtualized layouts like UniformGridLayout.
if (e.TargetObject != this && e.TargetObject is UIElement targetElement)
{
// Verify the target element is actually a descendant of this ItemsRepeater
if (!IsAncestorOf(targetElement))
{
// Not our element, let the base class handle it
base.OnRequestBringIntoView(e);
return;
}

// Walk up the visual tree to find an ItemsRepeaterScrollHost
DependencyObject parent = this;
while (parent != null)
{
parent = VisualTreeHelper.GetParent(parent);
if (parent is ItemsRepeaterScrollHost scrollHost)
{
// Found a scroll host - forward the request to it.
// Using alignment 0.0 means align to the top/left edge of the viewport.
// The scroll host will calculate the correct scroll position based on
// the element's layout bounds.
scrollHost.StartBringIntoView(
targetElement,
alignmentX: DefaultBringIntoViewAlignment,
alignmentY: DefaultBringIntoViewAlignment,
offsetX: DefaultBringIntoViewOffset,
offsetY: DefaultBringIntoViewOffset,
animate: DefaultBringIntoViewAnimate);

// Mark the event as handled so it doesn't bubble up further
e.Handled = true;
return;
}
}
}

// No scroll host found, use default behavior
base.OnRequestBringIntoView(e);
}

private bool IsAncestorOf(DependencyObject descendant)
{
if (descendant == null)
return false;

DependencyObject current = descendant;
while (current != null)
{
if (current == this)
return true;

current = VisualTreeHelper.GetParent(current);
}

return false;
}

protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)
{
return new RepeaterUIElementCollection(this, logicalParent);
Expand Down