feat: add mvvm demo.

This commit is contained in:
Dong Bin
2025-07-02 22:31:16 +08:00
parent 881b9ca7d3
commit 6deccdc1ac
4 changed files with 220 additions and 82 deletions

View File

@@ -3,7 +3,9 @@ using Avalonia.Animation;
using Avalonia.Animation.Easings;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Styling;
using Avalonia.VisualTree;
namespace Ursa.Controls;
@@ -18,11 +20,11 @@ public class Anchor: SelectingItemsControl
set => SetValue(TargetContainerProperty, value);
}
public static readonly AttachedProperty<string> AnchorIdProperty =
AvaloniaProperty.RegisterAttached<Anchor, Control, string>("AnchorId");
public static readonly AttachedProperty<string?> AnchorIdProperty =
AvaloniaProperty.RegisterAttached<Anchor, Visual, string?>("AnchorId");
public static void SetAnchorId(Control obj, string value) => obj.SetValue(AnchorIdProperty, value);
public static string GetAnchorId(Control obj) => obj.GetValue(AnchorIdProperty);
public static void SetAnchorId(Visual obj, string? value) => obj.SetValue(AnchorIdProperty, value);
public static string? GetAnchorId(Visual obj) => obj.GetValue(AnchorIdProperty);
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
@@ -40,24 +42,16 @@ public class Anchor: SelectingItemsControl
{
if (TargetContainer is null)
return;
var target = TargetContainer.FindControl<Control>(anchorId);
if (target is null)
return;
var targetPosition = target.TranslatePoint(new Point(0, 0), TargetContainer);
if (targetPosition.HasValue)
{
TargetContainer.Offset = new Vector(0, targetPosition.Value.Y);
}
var target = TargetContainer.GetVisualDescendants().FirstOrDefault(a=>Anchor.GetAnchorId(a) == anchorId);
if (target is null) return;
ScrollToAnchor(target);
}
internal void ScrollToAnchor(Control target)
internal void ScrollToAnchor(Visual target)
{
if (TargetContainer is null)
return;
TargetContainer.Loaded += OnTargetLoaded;
var targetPosition = target.TranslatePoint(new Point(0, 0), TargetContainer);
if (targetPosition.HasValue)
{
@@ -95,5 +89,25 @@ public class Anchor: SelectingItemsControl
// TargetContainer.Offset = TargetContainer.Offset.WithY(TargetContainer.Offset.Y + targetPosition.Value.Y);
}
}
private void OnTargetLoaded(object sender, RoutedEventArgs e)
{
if (sender is ScrollViewer scrollViewer)
{
scrollViewer.Loaded -= OnTargetLoaded;
if (scrollViewer.Content is Visual target)
{
var anchorId = GetAnchorId(target);
if (!string.IsNullOrEmpty(anchorId))
{
ScrollToAnchor(anchorId);
}
}
}
}
public void InvalidatePositions()
{
}
}

View File

@@ -17,12 +17,12 @@ public class AnchorItem: ContentControl
set => SetValue(TargetProperty, value);
}
public static readonly StyledProperty<string?> AnchorNameProperty = AvaloniaProperty.Register<AnchorItem, string?>(
nameof(AnchorName));
public string? AnchorName
public static readonly StyledProperty<string?> AnchorIdProperty = AvaloniaProperty.Register<AnchorItem, string?>(
nameof(AnchorId));
public string? AnchorId
{
get => GetValue(AnchorNameProperty);
set => SetValue(AnchorNameProperty, value);
get => GetValue(AnchorIdProperty);
set => SetValue(AnchorIdProperty, value);
}
private Anchor? _root;
@@ -43,5 +43,9 @@ public class AnchorItem: ContentControl
{
_root.ScrollToAnchor(Target);
}
else if (!string.IsNullOrEmpty(AnchorId))
{
_root.ScrollToAnchor(AnchorId);
}
}
}