Merge pull request #588 from irihitech/selection
Fix various issues for SelectionList
This commit is contained in:
@@ -12,10 +12,14 @@
|
|||||||
x:DataType="vm:SelectionListDemoViewModel"
|
x:DataType="vm:SelectionListDemoViewModel"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<StackPanel HorizontalAlignment="Left">
|
<StackPanel HorizontalAlignment="Left">
|
||||||
<u:SelectionList ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
|
<u:SelectionList
|
||||||
|
Width="600"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
ItemsSource="{Binding Items}"
|
||||||
|
SelectedItem="{Binding SelectedItem}">
|
||||||
<u:SelectionList.ItemsPanel>
|
<u:SelectionList.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<StackPanel Orientation="Horizontal" />
|
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" />
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</u:SelectionList.ItemsPanel>
|
</u:SelectionList.ItemsPanel>
|
||||||
</u:SelectionList>
|
</u:SelectionList>
|
||||||
@@ -36,9 +40,9 @@
|
|||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Panel Height="40">
|
<Panel Height="40">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Classes.Active="{Binding $parent[u:SelectionListItem].IsSelected, Mode=OneWay}"
|
|
||||||
Margin="8,0"
|
Margin="8,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
|
Classes.Active="{Binding $parent[u:SelectionListItem].IsSelected, Mode=OneWay}"
|
||||||
Text="{Binding}">
|
Text="{Binding}">
|
||||||
<TextBlock.Styles>
|
<TextBlock.Styles>
|
||||||
<Style Selector="TextBlock.Active">
|
<Style Selector="TextBlock.Active">
|
||||||
@@ -50,6 +54,14 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</u:SelectionList.ItemTemplate>
|
</u:SelectionList.ItemTemplate>
|
||||||
</u:SelectionList>
|
</u:SelectionList>
|
||||||
<Button Command="{Binding Clear}">Clear</Button>
|
<SplitButton Content="Button With Selection">
|
||||||
|
<SplitButton.Flyout>
|
||||||
|
<Flyout>
|
||||||
|
<u:SelectionList ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" />
|
||||||
|
</Flyout>
|
||||||
|
</SplitButton.Flyout>
|
||||||
|
</SplitButton>
|
||||||
|
<Button Margin="0 12" Command="{Binding Clear}">Clear</Button>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -14,33 +14,34 @@ using Irihi.Avalonia.Shared.Helpers;
|
|||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
[TemplatePart(PART_Indicator, typeof(ContentPresenter))]
|
[TemplatePart(PART_Indicator, typeof(ContentPresenter))]
|
||||||
public class SelectionList: SelectingItemsControl
|
public class SelectionList : SelectingItemsControl
|
||||||
{
|
{
|
||||||
public const string PART_Indicator = "PART_Indicator";
|
public const string PART_Indicator = "PART_Indicator";
|
||||||
private static readonly FuncTemplate<Panel?> DefaultPanel = new(() => new StackPanel());
|
private static readonly FuncTemplate<Panel?> DefaultPanel = new(() => new StackPanel());
|
||||||
|
|
||||||
|
public static readonly StyledProperty<Control?> IndicatorProperty =
|
||||||
|
AvaloniaProperty.Register<SelectionList, Control?>(
|
||||||
|
nameof(Indicator));
|
||||||
|
|
||||||
private ImplicitAnimationCollection? _implicitAnimations;
|
private ImplicitAnimationCollection? _implicitAnimations;
|
||||||
private ContentPresenter? _indicator;
|
private ContentPresenter? _indicator;
|
||||||
|
|
||||||
public static readonly StyledProperty<Control?> IndicatorProperty = AvaloniaProperty.Register<SelectionList, Control?>(
|
static SelectionList()
|
||||||
nameof(Indicator));
|
{
|
||||||
|
SelectionModeProperty.OverrideMetadata<SelectionList>(
|
||||||
|
new StyledPropertyMetadata<SelectionMode>(
|
||||||
|
SelectionMode.Single,
|
||||||
|
coerce: (_, _) => SelectionMode.Single)
|
||||||
|
);
|
||||||
|
SelectedItemProperty.Changed.AddClassHandler<SelectionList, object?>((list, args) =>
|
||||||
|
list.OnSelectedItemChanged(args));
|
||||||
|
}
|
||||||
|
|
||||||
public Control? Indicator
|
public Control? Indicator
|
||||||
{
|
{
|
||||||
get => GetValue(IndicatorProperty);
|
get => GetValue(IndicatorProperty);
|
||||||
set => SetValue(IndicatorProperty, value);
|
set => SetValue(IndicatorProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SelectionList()
|
|
||||||
{
|
|
||||||
SelectionModeProperty.OverrideMetadata<SelectionList>(
|
|
||||||
new StyledPropertyMetadata<SelectionMode>(
|
|
||||||
defaultValue: SelectionMode.Single,
|
|
||||||
coerce: (_, _) => SelectionMode.Single)
|
|
||||||
);
|
|
||||||
SelectedItemProperty.Changed.AddClassHandler<SelectionList, object?>((list, args) =>
|
|
||||||
list.OnSelectedItemChanged(args));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSelectedItemChanged(AvaloniaPropertyChangedEventArgs<object?> args)
|
private void OnSelectedItemChanged(AvaloniaPropertyChangedEventArgs<object?> args)
|
||||||
{
|
{
|
||||||
@@ -50,31 +51,36 @@ public class SelectionList: SelectingItemsControl
|
|||||||
OpacityProperty.SetValue(0d, _indicator);
|
OpacityProperty.SetValue(0d, _indicator);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var container = ContainerFromItem(newValue);
|
var container = ContainerFromItem(newValue);
|
||||||
if (container is null)
|
if (container is null)
|
||||||
{
|
{
|
||||||
OpacityProperty.SetValue(0d, _indicator);
|
OpacityProperty.SetValue(0d, _indicator);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpacityProperty.SetValue(1d, _indicator);
|
OpacityProperty.SetValue(1d, _indicator);
|
||||||
InvalidateMeasure();
|
InvalidateMeasure();
|
||||||
InvalidateArrange();
|
// InvalidateArrange();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Size ArrangeOverride(Size finalSize)
|
protected override Size ArrangeOverride(Size finalSize)
|
||||||
{
|
{
|
||||||
var size = base.ArrangeOverride(finalSize);
|
var size = base.ArrangeOverride(finalSize);
|
||||||
if(_indicator is not null && SelectedItem is not null)
|
if (_indicator is not null && SelectedItem is not null)
|
||||||
{
|
{
|
||||||
var container = ContainerFromItem(SelectedItem);
|
var container = ContainerFromItem(SelectedItem);
|
||||||
if (container is null) return size;
|
if (container is null) return size;
|
||||||
_indicator.Arrange(container.Bounds);
|
var bounds = container.Bounds;
|
||||||
|
if (ItemsPanelRoot?.Bounds.Position is { } p) bounds = bounds.Translate(p);
|
||||||
|
_indicator.Arrange(bounds);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This is a hack. The indicator is not visible, so we arrange it to a 1x1 rectangle
|
// This is a hack. The indicator is not visible, so we arrange it to a 1x1 rectangle
|
||||||
_indicator?.Arrange(new Rect(new Point(), new Size(1, 1)));
|
_indicator?.Arrange(new Rect(new Point(), new Size(1, 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,19 +97,21 @@ public class SelectionList: SelectingItemsControl
|
|||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnApplyTemplate(e);
|
base.OnApplyTemplate(e);
|
||||||
_indicator= e.NameScope.Find<ContentPresenter>(PART_Indicator);
|
_indicator = e.NameScope.Find<ContentPresenter>(PART_Indicator);
|
||||||
EnsureIndicatorAnimation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnLoaded(RoutedEventArgs e)
|
protected override void OnLoaded(RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnLoaded(e);
|
base.OnLoaded(e);
|
||||||
if(_indicator is not null && SelectedItem is not null)
|
EnsureIndicatorAnimation();
|
||||||
|
if (_indicator is not null && SelectedItem is not null)
|
||||||
{
|
{
|
||||||
var container = ContainerFromItem(SelectedItem);
|
var container = ContainerFromItem(SelectedItem);
|
||||||
if (container is null) return;
|
if (container is null) return;
|
||||||
_indicator.Opacity = 1;
|
_indicator.Opacity = 1;
|
||||||
_indicator.Arrange(container.Bounds);
|
var bounds = container.Bounds;
|
||||||
|
if (ItemsPanelRoot?.Bounds.Position is { } p) bounds = bounds.Translate(p);
|
||||||
|
_indicator.Arrange(bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,10 +121,7 @@ public class SelectionList: SelectingItemsControl
|
|||||||
{
|
{
|
||||||
_indicator.Opacity = 0;
|
_indicator.Opacity = 0;
|
||||||
SetUpAnimation();
|
SetUpAnimation();
|
||||||
if (ElementComposition.GetElementVisual(_indicator) is { } v)
|
if (ElementComposition.GetElementVisual(_indicator) is { } v) v.ImplicitAnimations = _implicitAnimations;
|
||||||
{
|
|
||||||
v.ImplicitAnimations = _implicitAnimations;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +131,7 @@ public class SelectionList: SelectingItemsControl
|
|||||||
Selection.Clear();
|
Selection.Clear();
|
||||||
Selection.Select(index);
|
Selection.Select(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetUpAnimation()
|
private void SetUpAnimation()
|
||||||
{
|
{
|
||||||
if (_implicitAnimations != null) return;
|
if (_implicitAnimations != null) return;
|
||||||
@@ -151,15 +156,13 @@ public class SelectionList: SelectingItemsControl
|
|||||||
_implicitAnimations[nameof(CompositionVisual.Size)] = sizeAnimation;
|
_implicitAnimations[nameof(CompositionVisual.Size)] = sizeAnimation;
|
||||||
_implicitAnimations[nameof(CompositionVisual.Opacity)] = opacityAnimation;
|
_implicitAnimations[nameof(CompositionVisual.Opacity)] = opacityAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnKeyDown(KeyEventArgs e)
|
protected override void OnKeyDown(KeyEventArgs e)
|
||||||
{
|
{
|
||||||
var hotkeys = Application.Current!.PlatformSettings?.HotkeyConfiguration;
|
var hotkeys = Application.Current!.PlatformSettings?.HotkeyConfiguration;
|
||||||
|
|
||||||
if (e.Key.ToNavigationDirection() is { } direction && direction.IsDirectional())
|
if (e.Key.ToNavigationDirection() is { } direction && direction.IsDirectional())
|
||||||
{
|
|
||||||
e.Handled |= MoveSelection(direction, WrapSelection);
|
e.Handled |= MoveSelection(direction, WrapSelection);
|
||||||
}
|
|
||||||
base.OnKeyDown(e);
|
base.OnKeyDown(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user