feat: add mvvm demo.
This commit is contained in:
@@ -5,65 +5,169 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:u="https://irihi.tech/ursa"
|
xmlns:u="https://irihi.tech/ursa"
|
||||||
|
xmlns:viewModels="clr-namespace:Ursa.Demo.ViewModels"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
|
x:DataType="viewModels:AnchorDemoViewModel"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid ColumnDefinitions="*, Auto">
|
<TabControl>
|
||||||
<ScrollViewer
|
<TabItem Header="XAML Inline">
|
||||||
Name="container"
|
<Grid ColumnDefinitions="*, Auto">
|
||||||
Grid.Column="0"
|
<ScrollViewer
|
||||||
VerticalAlignment="Stretch">
|
Name="container1"
|
||||||
<StackPanel>
|
Grid.Column="0"
|
||||||
<Rectangle
|
VerticalAlignment="Stretch">
|
||||||
Name="rectangle1"
|
<StackPanel>
|
||||||
Height="300"
|
<StackPanel.Styles>
|
||||||
HorizontalAlignment="Stretch"
|
<Style Selector="TextBlock">
|
||||||
Fill="{DynamicResource SemiRed2}" />
|
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||||
<Rectangle
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
Name="rectangle2"
|
</Style>
|
||||||
Height="300"
|
</StackPanel.Styles>
|
||||||
HorizontalAlignment="Stretch"
|
<Border
|
||||||
Fill="{DynamicResource SemiPink1}" />
|
Name="a1"
|
||||||
<Rectangle
|
Height="300"
|
||||||
Name="rectangle3"
|
HorizontalAlignment="Stretch"
|
||||||
Height="300"
|
Background="{DynamicResource SemiRed2}">
|
||||||
HorizontalAlignment="Stretch"
|
<TextBlock Text="Border 1" />
|
||||||
Fill="{DynamicResource SemiPurple1}" />
|
</Border>
|
||||||
<Rectangle
|
<Border
|
||||||
Name="rectangle4"
|
Name="a2"
|
||||||
Height="300"
|
Height="300"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Fill="{DynamicResource SemiViolet1}" />
|
Background="{DynamicResource SemiPink1}">
|
||||||
<Rectangle
|
<TextBlock Text="Border 2" />
|
||||||
Name="rectangle5"
|
</Border>
|
||||||
Height="300"
|
<Border
|
||||||
HorizontalAlignment="Stretch"
|
Name="a3"
|
||||||
Fill="{DynamicResource SemiIndigo1}" />
|
Height="300"
|
||||||
<Rectangle
|
HorizontalAlignment="Stretch"
|
||||||
Name="rectangle6"
|
Background="{DynamicResource SemiPurple1}">
|
||||||
Height="300"
|
<TextBlock Text="Border 3" />
|
||||||
HorizontalAlignment="Stretch"
|
</Border>
|
||||||
Fill="{DynamicResource SemiBlue1}" />
|
<Border
|
||||||
<Rectangle
|
Name="a4"
|
||||||
Name="rectangle7"
|
Height="300"
|
||||||
Height="300"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalAlignment="Stretch"
|
Background="{DynamicResource SemiViolet1}">
|
||||||
Fill="{DynamicResource SemiLightBlue1}" />
|
<TextBlock Text="Border 4" />
|
||||||
</StackPanel>
|
</Border>
|
||||||
</ScrollViewer>
|
<Border
|
||||||
<u:Anchor
|
Name="a5"
|
||||||
Grid.Column="1"
|
Height="300"
|
||||||
Width="200"
|
HorizontalAlignment="Stretch"
|
||||||
Margin="24"
|
Background="{DynamicResource SemiIndigo1}">
|
||||||
TargetContainer="{Binding ElementName=container}">
|
<TextBlock Text="Border 5" />
|
||||||
<u:AnchorItem Content="Rectangle 1" Target="{Binding #rectangle1}" />
|
</Border>
|
||||||
<u:AnchorItem Content="Rectangle 2" Target="{Binding #rectangle2}" />
|
<Border
|
||||||
<u:AnchorItem Content="Rectangle 3" Target="{Binding #rectangle3}" />
|
Name="a6"
|
||||||
<u:AnchorItem Content="Rectangle 4" Target="{Binding #rectangle4}" />
|
Height="300"
|
||||||
<u:AnchorItem Content="Rectangle 5" Target="{Binding #rectangle5}" />
|
HorizontalAlignment="Stretch"
|
||||||
<u:AnchorItem Content="Rectangle 6" Target="{Binding #rectangle6}" />
|
Background="{DynamicResource SemiBlue1}">
|
||||||
<u:AnchorItem Content="Rectangle 7" Target="{Binding #rectangle7}" />
|
<TextBlock Text="Border 6" />
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Name="a7"
|
||||||
|
Height="300"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Background="{DynamicResource SemiLightBlue1}">
|
||||||
|
<TextBlock Text="Border 7" />
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
<u:Anchor
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="24"
|
||||||
|
TargetContainer="{Binding ElementName=container1}">
|
||||||
|
<u:AnchorItem Content="Rectangle 1" Target="{Binding #a1}" />
|
||||||
|
<u:AnchorItem Content="Rectangle 2" Target="{Binding #a2}" />
|
||||||
|
<u:AnchorItem Content="Rectangle 3" Target="{Binding #a3}" />
|
||||||
|
<u:AnchorItem Content="Rectangle 4" Target="{Binding #a4}" />
|
||||||
|
<u:AnchorItem Content="Rectangle 5" Target="{Binding #a5}" />
|
||||||
|
<u:AnchorItem Content="Rectangle 6" Target="{Binding #a6}" />
|
||||||
|
<u:AnchorItem Content="Rectangle 7" Target="{Binding #a7}" />
|
||||||
|
|
||||||
</u:Anchor>
|
</u:Anchor>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</TabItem>
|
||||||
|
<TabItem Header="MVVM">
|
||||||
|
<Grid ColumnDefinitions="*, Auto">
|
||||||
|
<ScrollViewer
|
||||||
|
Name="container2"
|
||||||
|
Grid.Column="0"
|
||||||
|
VerticalAlignment="Stretch">
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel.Styles>
|
||||||
|
<Style Selector="TextBlock">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
</Style>
|
||||||
|
</StackPanel.Styles>
|
||||||
|
<Border
|
||||||
|
Height="300"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
u:Anchor.AnchorId="anchor1"
|
||||||
|
Background="{DynamicResource SemiRed2}">
|
||||||
|
<TextBlock Text="Border 1" />
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Height="300"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
u:Anchor.AnchorId="anchor2"
|
||||||
|
Background="{DynamicResource SemiPink1}">
|
||||||
|
<TextBlock Text="Border 2" />
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Height="300"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
u:Anchor.AnchorId="anchor3"
|
||||||
|
Background="{DynamicResource SemiPurple1}">
|
||||||
|
<TextBlock Text="Border 3" />
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Height="300"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
u:Anchor.AnchorId="anchor4"
|
||||||
|
Background="{DynamicResource SemiViolet1}">
|
||||||
|
<TextBlock Text="Border 4" />
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Height="300"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
u:Anchor.AnchorId="anchor5"
|
||||||
|
Background="{DynamicResource SemiIndigo1}">
|
||||||
|
<TextBlock Text="Border 5" />
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Height="300"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
u:Anchor.AnchorId="anchor6"
|
||||||
|
Background="{DynamicResource SemiBlue1}">
|
||||||
|
<TextBlock Text="Border 6" />
|
||||||
|
</Border>
|
||||||
|
<Border
|
||||||
|
Height="300"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
u:Anchor.AnchorId="anchor7"
|
||||||
|
Background="{DynamicResource SemiLightBlue1}">
|
||||||
|
<TextBlock Text="Border 7" />
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
<u:Anchor
|
||||||
|
Grid.Column="1"
|
||||||
|
MinWidth="300"
|
||||||
|
ItemsSource="{Binding AnchorItems}"
|
||||||
|
TargetContainer="{Binding #container2}">
|
||||||
|
<u:Anchor.Styles>
|
||||||
|
<Style x:DataType="viewModels:AnchorItemViewModel" Selector="u|AnchorItem">
|
||||||
|
<Setter Property="AnchorId" Value="{Binding AnchorId}" />
|
||||||
|
<Setter Property="Content" Value="{Binding Header}" />
|
||||||
|
</Style>
|
||||||
|
</u:Anchor.Styles>
|
||||||
|
</u:Anchor>
|
||||||
|
</Grid>
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
|
</UserControl>
|
||||||
@@ -1,8 +1,24 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
|
||||||
namespace Ursa.Demo.ViewModels;
|
namespace Ursa.Demo.ViewModels;
|
||||||
|
|
||||||
public partial class AnchorDemoViewModel: ObservableObject
|
public partial class AnchorDemoViewModel: ObservableObject
|
||||||
{
|
{
|
||||||
|
public List<AnchorItemViewModel> AnchorItems { get; } = new()
|
||||||
|
{
|
||||||
|
new AnchorItemViewModel { AnchorId = "anchor1", Header = "Anchor 1" },
|
||||||
|
new AnchorItemViewModel { AnchorId = "anchor2", Header = "Anchor 2" },
|
||||||
|
new AnchorItemViewModel { AnchorId = "anchor3", Header = "Anchor 3" },
|
||||||
|
new AnchorItemViewModel { AnchorId = "anchor4", Header = "Anchor 4" },
|
||||||
|
new AnchorItemViewModel { AnchorId = "anchor5", Header = "Anchor 5" },
|
||||||
|
new AnchorItemViewModel { AnchorId = "anchor6", Header = "Anchor 6" },
|
||||||
|
new AnchorItemViewModel { AnchorId = "anchor7", Header = "Anchor 7" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class AnchorItemViewModel: ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty] private string? _anchorId;
|
||||||
|
[ObservableProperty] private string? _header;
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,9 @@ using Avalonia.Animation;
|
|||||||
using Avalonia.Animation.Easings;
|
using Avalonia.Animation.Easings;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
@@ -18,11 +20,11 @@ public class Anchor: SelectingItemsControl
|
|||||||
set => SetValue(TargetContainerProperty, value);
|
set => SetValue(TargetContainerProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly AttachedProperty<string> AnchorIdProperty =
|
public static readonly AttachedProperty<string?> AnchorIdProperty =
|
||||||
AvaloniaProperty.RegisterAttached<Anchor, Control, string>("AnchorId");
|
AvaloniaProperty.RegisterAttached<Anchor, Visual, string?>("AnchorId");
|
||||||
|
|
||||||
public static void SetAnchorId(Control obj, string value) => obj.SetValue(AnchorIdProperty, value);
|
public static void SetAnchorId(Visual obj, string? value) => obj.SetValue(AnchorIdProperty, value);
|
||||||
public static string GetAnchorId(Control obj) => obj.GetValue(AnchorIdProperty);
|
public static string? GetAnchorId(Visual obj) => obj.GetValue(AnchorIdProperty);
|
||||||
|
|
||||||
|
|
||||||
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
|
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
|
||||||
@@ -40,24 +42,16 @@ public class Anchor: SelectingItemsControl
|
|||||||
{
|
{
|
||||||
if (TargetContainer is null)
|
if (TargetContainer is null)
|
||||||
return;
|
return;
|
||||||
|
var target = TargetContainer.GetVisualDescendants().FirstOrDefault(a=>Anchor.GetAnchorId(a) == anchorId);
|
||||||
var target = TargetContainer.FindControl<Control>(anchorId);
|
if (target is null) return;
|
||||||
if (target is null)
|
ScrollToAnchor(target);
|
||||||
return;
|
|
||||||
|
|
||||||
var targetPosition = target.TranslatePoint(new Point(0, 0), TargetContainer);
|
|
||||||
if (targetPosition.HasValue)
|
|
||||||
{
|
|
||||||
TargetContainer.Offset = new Vector(0, targetPosition.Value.Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ScrollToAnchor(Control target)
|
internal void ScrollToAnchor(Visual target)
|
||||||
{
|
{
|
||||||
if (TargetContainer is null)
|
if (TargetContainer is null)
|
||||||
return;
|
return;
|
||||||
|
TargetContainer.Loaded += OnTargetLoaded;
|
||||||
var targetPosition = target.TranslatePoint(new Point(0, 0), TargetContainer);
|
var targetPosition = target.TranslatePoint(new Point(0, 0), TargetContainer);
|
||||||
if (targetPosition.HasValue)
|
if (targetPosition.HasValue)
|
||||||
{
|
{
|
||||||
@@ -95,5 +89,25 @@ public class Anchor: SelectingItemsControl
|
|||||||
// TargetContainer.Offset = TargetContainer.Offset.WithY(TargetContainer.Offset.Y + targetPosition.Value.Y);
|
// 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()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -17,12 +17,12 @@ public class AnchorItem: ContentControl
|
|||||||
set => SetValue(TargetProperty, value);
|
set => SetValue(TargetProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly StyledProperty<string?> AnchorNameProperty = AvaloniaProperty.Register<AnchorItem, string?>(
|
public static readonly StyledProperty<string?> AnchorIdProperty = AvaloniaProperty.Register<AnchorItem, string?>(
|
||||||
nameof(AnchorName));
|
nameof(AnchorId));
|
||||||
public string? AnchorName
|
public string? AnchorId
|
||||||
{
|
{
|
||||||
get => GetValue(AnchorNameProperty);
|
get => GetValue(AnchorIdProperty);
|
||||||
set => SetValue(AnchorNameProperty, value);
|
set => SetValue(AnchorIdProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Anchor? _root;
|
private Anchor? _root;
|
||||||
@@ -43,5 +43,9 @@ public class AnchorItem: ContentControl
|
|||||||
{
|
{
|
||||||
_root.ScrollToAnchor(Target);
|
_root.ScrollToAnchor(Target);
|
||||||
}
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(AnchorId))
|
||||||
|
{
|
||||||
|
_root.ScrollToAnchor(AnchorId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user