Browse Source

remove IScrollSnapPointsInfo implementation from ItemsControl

pull/11752/head
Emmanuel Hansen 3 years ago
parent
commit
6b06e5c5fb
  1. 86
      src/Avalonia.Controls/ItemsControl.cs
  2. 120
      src/Avalonia.Controls/Presenters/ItemsPresenter.cs
  3. 65
      src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
  4. 2
      src/Avalonia.Themes.Fluent/Controls/ItemsControl.xaml
  5. 2
      src/Avalonia.Themes.Fluent/Controls/ListBox.xaml
  6. 2
      src/Avalonia.Themes.Simple/Controls/ItemsControl.xaml
  7. 2
      src/Avalonia.Themes.Simple/Controls/ListBox.xaml

86
src/Avalonia.Controls/ItemsControl.cs

@ -23,7 +23,7 @@ namespace Avalonia.Controls
/// Displays a collection of items. /// Displays a collection of items.
/// </summary> /// </summary>
[PseudoClasses(":empty", ":singleitem")] [PseudoClasses(":empty", ":singleitem")]
public class ItemsControl : TemplatedControl, IChildIndexProvider, IScrollSnapPointsInfo public class ItemsControl : TemplatedControl, IChildIndexProvider
{ {
/// <summary> /// <summary>
/// The default value for the <see cref="ItemsPanel"/> property. /// The default value for the <see cref="ItemsPanel"/> property.
@ -67,18 +67,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty<IBinding?> DisplayMemberBindingProperty = public static readonly StyledProperty<IBinding?> DisplayMemberBindingProperty =
AvaloniaProperty.Register<ItemsControl, IBinding?>(nameof(DisplayMemberBinding)); AvaloniaProperty.Register<ItemsControl, IBinding?>(nameof(DisplayMemberBinding));
/// <summary>
/// Defines the <see cref="AreHorizontalSnapPointsRegular"/> property.
/// </summary>
public static readonly StyledProperty<bool> AreHorizontalSnapPointsRegularProperty =
AvaloniaProperty.Register<ItemsControl, bool>(nameof(AreHorizontalSnapPointsRegular));
/// <summary>
/// Defines the <see cref="AreVerticalSnapPointsRegular"/> property.
/// </summary>
public static readonly StyledProperty<bool> AreVerticalSnapPointsRegularProperty =
AvaloniaProperty.Register<ItemsControl, bool>(nameof(AreVerticalSnapPointsRegular));
/// <summary> /// <summary>
/// Gets or sets the <see cref="IBinding"/> to use for binding to the display member of each item. /// Gets or sets the <see cref="IBinding"/> to use for binding to the display member of each item.
/// </summary> /// </summary>
@ -249,64 +237,6 @@ namespace Avalonia.Controls
/// </remarks> /// </remarks>
public event EventHandler<ContainerClearingEventArgs>? ContainerClearing; public event EventHandler<ContainerClearingEventArgs>? ContainerClearing;
/// <inheritdoc />
public event EventHandler<RoutedEventArgs> HorizontalSnapPointsChanged
{
add
{
if (_itemsPresenter != null)
{
_itemsPresenter.HorizontalSnapPointsChanged += value;
}
}
remove
{
if (_itemsPresenter != null)
{
_itemsPresenter.HorizontalSnapPointsChanged -= value;
}
}
}
/// <inheritdoc />
public event EventHandler<RoutedEventArgs> VerticalSnapPointsChanged
{
add
{
if (_itemsPresenter != null)
{
_itemsPresenter.VerticalSnapPointsChanged += value;
}
}
remove
{
if (_itemsPresenter != null)
{
_itemsPresenter.VerticalSnapPointsChanged -= value;
}
}
}
/// <summary>
/// Gets or sets whether the horizontal snap points for the <see cref="ItemsControl"/> are equidistant from each other.
/// </summary>
public bool AreHorizontalSnapPointsRegular
{
get => GetValue(AreHorizontalSnapPointsRegularProperty);
set => SetValue(AreHorizontalSnapPointsRegularProperty, value);
}
/// <summary>
/// Gets or sets whether the vertical snap points for the <see cref="ItemsControl"/> are equidistant from each other.
/// </summary>
public bool AreVerticalSnapPointsRegular
{
get => GetValue(AreVerticalSnapPointsRegularProperty);
set => SetValue(AreVerticalSnapPointsRegularProperty, value);
}
/// <summary> /// <summary>
/// Gets a default recycle key that can be used when an <see cref="ItemsControl"/> supports /// Gets a default recycle key that can be used when an <see cref="ItemsControl"/> supports
/// a single container type. /// a single container type.
@ -896,19 +826,5 @@ namespace Avalonia.Controls
count = ItemsView.Count; count = ItemsView.Count;
return true; return true;
} }
/// <inheritdoc />
public IReadOnlyList<double> GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment)
{
return _itemsPresenter?.GetIrregularSnapPoints(orientation, snapPointsAlignment) ?? new List<double>();
}
/// <inheritdoc />
public double GetRegularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment, out double offset)
{
offset = 0;
return _itemsPresenter?.GetRegularSnapPoints(orientation, snapPointsAlignment, out offset) ?? 0;
}
} }
} }

120
src/Avalonia.Controls/Presenters/ItemsPresenter.cs

@ -11,7 +11,7 @@ namespace Avalonia.Controls.Presenters
/// <summary> /// <summary>
/// Presents items inside an <see cref="Avalonia.Controls.ItemsControl"/>. /// Presents items inside an <see cref="Avalonia.Controls.ItemsControl"/>.
/// </summary> /// </summary>
public class ItemsPresenter : Control, ILogicalScrollable, IScrollSnapPointsInfo public class ItemsPresenter : Control, ILogicalScrollable
{ {
/// <summary> /// <summary>
/// Defines the <see cref="ItemsPanel"/> property. /// Defines the <see cref="ItemsPanel"/> property.
@ -21,37 +21,8 @@ namespace Avalonia.Controls.Presenters
private PanelContainerGenerator? _generator; private PanelContainerGenerator? _generator;
private ILogicalScrollable? _logicalScrollable; private ILogicalScrollable? _logicalScrollable;
private IScrollSnapPointsInfo? _scrollSnapPointsInfo;
private EventHandler? _scrollInvalidated; private EventHandler? _scrollInvalidated;
/// <summary>
/// Defines the <see cref="AreHorizontalSnapPointsRegular"/> property.
/// </summary>
public static readonly StyledProperty<bool> AreHorizontalSnapPointsRegularProperty =
AvaloniaProperty.Register<ItemsPresenter, bool>(nameof(AreHorizontalSnapPointsRegular));
/// <summary>
/// Defines the <see cref="AreVerticalSnapPointsRegular"/> property.
/// </summary>
public static readonly StyledProperty<bool> AreVerticalSnapPointsRegularProperty =
AvaloniaProperty.Register<ItemsPresenter, bool>(nameof(AreVerticalSnapPointsRegular));
/// <summary>
/// Defines the <see cref="HorizontalSnapPointsChanged"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> HorizontalSnapPointsChangedEvent =
RoutedEvent.Register<ItemsPresenter, RoutedEventArgs>(
nameof(HorizontalSnapPointsChanged),
RoutingStrategies.Bubble);
/// <summary>
/// Defines the <see cref="VerticalSnapPointsChanged"/> event.
/// </summary>
public static readonly RoutedEvent<RoutedEventArgs> VerticalSnapPointsChangedEvent =
RoutedEvent.Register<ItemsPresenter, RoutedEventArgs>(
nameof(VerticalSnapPointsChanged),
RoutingStrategies.Bubble);
event EventHandler? ILogicalScrollable.ScrollInvalidated event EventHandler? ILogicalScrollable.ScrollInvalidated
{ {
add => _scrollInvalidated += value; add => _scrollInvalidated += value;
@ -107,47 +78,12 @@ namespace Avalonia.Controls.Presenters
} }
} }
/// <summary>
/// Occurs when the measurements for horizontal snap points change.
/// </summary>
public event EventHandler<RoutedEventArgs>? HorizontalSnapPointsChanged
{
add => AddHandler(HorizontalSnapPointsChangedEvent, value);
remove => RemoveHandler(HorizontalSnapPointsChangedEvent, value);
}
/// <summary>
/// Occurs when the measurements for vertical snap points change.
/// </summary>
public event EventHandler<RoutedEventArgs>? VerticalSnapPointsChanged
{
add => AddHandler(VerticalSnapPointsChangedEvent, value);
remove => RemoveHandler(VerticalSnapPointsChangedEvent, value);
}
bool ILogicalScrollable.IsLogicalScrollEnabled => _logicalScrollable?.IsLogicalScrollEnabled ?? false; bool ILogicalScrollable.IsLogicalScrollEnabled => _logicalScrollable?.IsLogicalScrollEnabled ?? false;
Size ILogicalScrollable.ScrollSize => _logicalScrollable?.ScrollSize ?? default; Size ILogicalScrollable.ScrollSize => _logicalScrollable?.ScrollSize ?? default;
Size ILogicalScrollable.PageScrollSize => _logicalScrollable?.PageScrollSize ?? default; Size ILogicalScrollable.PageScrollSize => _logicalScrollable?.PageScrollSize ?? default;
Size IScrollable.Extent => _logicalScrollable?.Extent ?? default; Size IScrollable.Extent => _logicalScrollable?.Extent ?? default;
Size IScrollable.Viewport => _logicalScrollable?.Viewport ?? default; Size IScrollable.Viewport => _logicalScrollable?.Viewport ?? default;
/// <summary>
/// Gets or sets whether the horizontal snap points for the <see cref="ItemsPresenter"/> are equidistant from each other.
/// </summary>
public bool AreHorizontalSnapPointsRegular
{
get { return GetValue(AreHorizontalSnapPointsRegularProperty); }
set { SetValue(AreHorizontalSnapPointsRegularProperty, value); }
}
/// <summary>
/// Gets or sets whether the vertical snap points for the <see cref="ItemsPresenter"/> are equidistant from each other.
/// </summary>
public bool AreVerticalSnapPointsRegular
{
get { return GetValue(AreVerticalSnapPointsRegularProperty); }
set { SetValue(AreVerticalSnapPointsRegularProperty, value); }
}
public override sealed void ApplyTemplate() public override sealed void ApplyTemplate()
{ {
@ -167,36 +103,14 @@ namespace Avalonia.Controls.Presenters
Panel.TemplatedParent = TemplatedParent; Panel.TemplatedParent = TemplatedParent;
Panel.IsItemsHost = true; Panel.IsItemsHost = true;
_scrollSnapPointsInfo = Panel as IScrollSnapPointsInfo;
LogicalChildren.Add(Panel); LogicalChildren.Add(Panel);
VisualChildren.Add(Panel); VisualChildren.Add(Panel);
if (_scrollSnapPointsInfo != null)
{
_scrollSnapPointsInfo.AreVerticalSnapPointsRegular = AreVerticalSnapPointsRegular;
_scrollSnapPointsInfo.AreHorizontalSnapPointsRegular = AreHorizontalSnapPointsRegular;
}
if (Panel is VirtualizingPanel v) if (Panel is VirtualizingPanel v)
v.Attach(ItemsControl); v.Attach(ItemsControl);
else else
CreateSimplePanelGenerator(); CreateSimplePanelGenerator();
if (Panel is IScrollSnapPointsInfo scrollSnapPointsInfo)
{
scrollSnapPointsInfo.VerticalSnapPointsChanged += (s, e) =>
{
e.RoutedEvent = VerticalSnapPointsChangedEvent;
RaiseEvent(e);
};
scrollSnapPointsInfo.HorizontalSnapPointsChanged += (s, e) =>
{
e.RoutedEvent = HorizontalSnapPointsChangedEvent;
RaiseEvent(e);
};
}
_logicalScrollable = Panel as ILogicalScrollable; _logicalScrollable = Panel as ILogicalScrollable;
if (_logicalScrollable is not null) if (_logicalScrollable is not null)
@ -240,16 +154,6 @@ namespace Avalonia.Controls.Presenters
ResetState(); ResetState();
InvalidateMeasure(); InvalidateMeasure();
} }
else if(change.Property == AreHorizontalSnapPointsRegularProperty)
{
if (_scrollSnapPointsInfo != null)
_scrollSnapPointsInfo.AreHorizontalSnapPointsRegular = AreHorizontalSnapPointsRegular;
}
else if (change.Property == AreVerticalSnapPointsRegularProperty)
{
if (_scrollSnapPointsInfo != null)
_scrollSnapPointsInfo.AreVerticalSnapPointsRegular = AreVerticalSnapPointsRegular;
}
} }
internal void Refresh() internal void Refresh()
@ -303,27 +207,5 @@ namespace Avalonia.Controls.Presenters
} }
private void OnLogicalScrollInvalidated(object? sender, EventArgs e) => _scrollInvalidated?.Invoke(this, e); private void OnLogicalScrollInvalidated(object? sender, EventArgs e) => _scrollInvalidated?.Invoke(this, e);
public IReadOnlyList<double> GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment)
{
if(Panel is IScrollSnapPointsInfo scrollSnapPointsInfo)
{
return scrollSnapPointsInfo.GetIrregularSnapPoints(orientation, snapPointsAlignment);
}
return new List<double>();
}
public double GetRegularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment, out double offset)
{
if (Panel is IScrollSnapPointsInfo scrollSnapPointsInfo)
{
return scrollSnapPointsInfo.GetRegularSnapPoints(orientation, snapPointsAlignment, out offset);
}
offset = 0;
return 0;
}
} }
} }

65
src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs

@ -7,6 +7,7 @@ using Avalonia.Input.GestureRecognizers;
using Avalonia.Utilities; using Avalonia.Utilities;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using System.Linq; using System.Linq;
using Avalonia.Interactivity;
namespace Avalonia.Controls.Presenters namespace Avalonia.Controls.Presenters
{ {
@ -99,6 +100,7 @@ namespace Avalonia.Controls.Presenters
private double _horizontalSnapPointOffset; private double _horizontalSnapPointOffset;
private CompositeDisposable? _ownerSubscriptions; private CompositeDisposable? _ownerSubscriptions;
private ScrollViewer? _owner; private ScrollViewer? _owner;
private IScrollSnapPointsInfo? _scrollSnapPointsInfo;
/// <summary> /// <summary>
/// Initializes static members of the <see cref="ScrollContentPresenter"/> class. /// Initializes static members of the <see cref="ScrollContentPresenter"/> class.
@ -570,7 +572,12 @@ namespace Avalonia.Controls.Presenters
private void OnScrollGestureInertiaStartingEnded(object? sender, ScrollGestureInertiaStartingEventArgs e) private void OnScrollGestureInertiaStartingEnded(object? sender, ScrollGestureInertiaStartingEventArgs e)
{ {
if (Content is not IScrollSnapPointsInfo) var scrollable = Content;
if (Content is ItemsControl itemsControl)
scrollable = itemsControl.Presenter?.Panel;
if (scrollable is not IScrollSnapPointsInfo)
return; return;
if (_scrollGestureSnapPoints == null) if (_scrollGestureSnapPoints == null)
@ -676,22 +683,6 @@ namespace Avalonia.Controls.Presenters
_owner?.SetCurrentValue(OffsetProperty, change.GetNewValue<Vector>()); _owner?.SetCurrentValue(OffsetProperty, change.GetNewValue<Vector>());
} }
else if (change.Property == ContentProperty)
{
if (change.OldValue is IScrollSnapPointsInfo oldSnapPointsInfo)
{
oldSnapPointsInfo.VerticalSnapPointsChanged -= ScrollSnapPointsInfoSnapPointsChanged;
oldSnapPointsInfo.HorizontalSnapPointsChanged += ScrollSnapPointsInfoSnapPointsChanged;
}
if (Content is IScrollSnapPointsInfo scrollSnapPointsInfo)
{
scrollSnapPointsInfo.VerticalSnapPointsChanged += ScrollSnapPointsInfoSnapPointsChanged;
scrollSnapPointsInfo.HorizontalSnapPointsChanged += ScrollSnapPointsInfoSnapPointsChanged;
}
UpdateSnapPoints();
}
else if (change.Property == ChildProperty) else if (change.Property == ChildProperty)
{ {
ChildChanged(change); ChildChanged(change);
@ -875,7 +866,9 @@ namespace Avalonia.Controls.Presenters
private void UpdateSnapPoints() private void UpdateSnapPoints()
{ {
if (Content is IScrollSnapPointsInfo scrollSnapPointsInfo) var scrollable = GetScrollSnapPointsInfo(Content);
if (scrollable is IScrollSnapPointsInfo scrollSnapPointsInfo)
{ {
_areVerticalSnapPointsRegular = scrollSnapPointsInfo.AreVerticalSnapPointsRegular; _areVerticalSnapPointsRegular = scrollSnapPointsInfo.AreVerticalSnapPointsRegular;
_areHorizontalSnapPointsRegular = scrollSnapPointsInfo.AreHorizontalSnapPointsRegular; _areHorizontalSnapPointsRegular = scrollSnapPointsInfo.AreHorizontalSnapPointsRegular;
@ -910,7 +903,9 @@ namespace Avalonia.Controls.Presenters
private Vector SnapOffset(Vector offset) private Vector SnapOffset(Vector offset)
{ {
if(Content is not IScrollSnapPointsInfo) var scrollable = GetScrollSnapPointsInfo(Content);
if(scrollable is null)
return offset; return offset;
var diff = GetAlignedDiff(); var diff = GetAlignedDiff();
@ -1012,5 +1007,37 @@ namespace Avalonia.Controls.Presenters
} }
return snapPoints[Math.Min(point, snapPoints.Count - 1)]; return snapPoints[Math.Min(point, snapPoints.Count - 1)];
} }
private IScrollSnapPointsInfo? GetScrollSnapPointsInfo(object? content)
{
var scrollable = content;
if (Content is ItemsControl itemsControl)
scrollable = itemsControl.Presenter?.Panel;
if (Content is ItemsPresenter itemsPresenter)
scrollable = itemsPresenter.Panel;
var snapPointsInfo = scrollable as IScrollSnapPointsInfo;
if(snapPointsInfo != _scrollSnapPointsInfo)
{
if(_scrollSnapPointsInfo != null)
{
_scrollSnapPointsInfo.VerticalSnapPointsChanged -= ScrollSnapPointsInfoSnapPointsChanged;
_scrollSnapPointsInfo.HorizontalSnapPointsChanged -= ScrollSnapPointsInfoSnapPointsChanged;
}
_scrollSnapPointsInfo = snapPointsInfo;
if(_scrollSnapPointsInfo != null)
{
_scrollSnapPointsInfo.VerticalSnapPointsChanged += ScrollSnapPointsInfoSnapPointsChanged;
_scrollSnapPointsInfo.HorizontalSnapPointsChanged += ScrollSnapPointsInfoSnapPointsChanged;
}
}
return snapPointsInfo;
}
} }
} }

2
src/Avalonia.Themes.Fluent/Controls/ItemsControl.xaml

@ -10,8 +10,6 @@
CornerRadius="{TemplateBinding CornerRadius}" CornerRadius="{TemplateBinding CornerRadius}"
Padding="{TemplateBinding Padding}"> Padding="{TemplateBinding Padding}">
<ItemsPresenter Name="PART_ItemsPresenter" <ItemsPresenter Name="PART_ItemsPresenter"
AreVerticalSnapPointsRegular="{TemplateBinding AreVerticalSnapPointsRegular}"
AreHorizontalSnapPointsRegular="{TemplateBinding AreHorizontalSnapPointsRegular}"
ItemsPanel="{TemplateBinding ItemsPanel}"/> ItemsPanel="{TemplateBinding ItemsPanel}"/>
</Border> </Border>
</ControlTemplate> </ControlTemplate>

2
src/Avalonia.Themes.Fluent/Controls/ListBox.xaml

@ -40,8 +40,6 @@
AllowAutoHide="{TemplateBinding (ScrollViewer.AllowAutoHide)}" AllowAutoHide="{TemplateBinding (ScrollViewer.AllowAutoHide)}"
BringIntoViewOnFocusChange="{TemplateBinding (ScrollViewer.BringIntoViewOnFocusChange)}"> BringIntoViewOnFocusChange="{TemplateBinding (ScrollViewer.BringIntoViewOnFocusChange)}">
<ItemsPresenter Name="PART_ItemsPresenter" <ItemsPresenter Name="PART_ItemsPresenter"
AreVerticalSnapPointsRegular="{TemplateBinding AreVerticalSnapPointsRegular}"
AreHorizontalSnapPointsRegular="{TemplateBinding AreHorizontalSnapPointsRegular}"
ItemsPanel="{TemplateBinding ItemsPanel}" ItemsPanel="{TemplateBinding ItemsPanel}"
Margin="{TemplateBinding Padding}"/> Margin="{TemplateBinding Padding}"/>
</ScrollViewer> </ScrollViewer>

2
src/Avalonia.Themes.Simple/Controls/ItemsControl.xaml

@ -11,8 +11,6 @@
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"> CornerRadius="{TemplateBinding CornerRadius}">
<ItemsPresenter Name="PART_ItemsPresenter" <ItemsPresenter Name="PART_ItemsPresenter"
AreVerticalSnapPointsRegular="{TemplateBinding AreVerticalSnapPointsRegular}"
AreHorizontalSnapPointsRegular="{TemplateBinding AreHorizontalSnapPointsRegular}"
ItemsPanel="{TemplateBinding ItemsPanel}" /> ItemsPanel="{TemplateBinding ItemsPanel}" />
</Border> </Border>
</ControlTemplate> </ControlTemplate>

2
src/Avalonia.Themes.Simple/Controls/ListBox.xaml

@ -27,8 +27,6 @@
HorizontalSnapPointsType="{TemplateBinding (ScrollViewer.HorizontalSnapPointsType)}"> HorizontalSnapPointsType="{TemplateBinding (ScrollViewer.HorizontalSnapPointsType)}">
<ItemsPresenter Name="PART_ItemsPresenter" <ItemsPresenter Name="PART_ItemsPresenter"
Margin="{TemplateBinding Padding}" Margin="{TemplateBinding Padding}"
AreVerticalSnapPointsRegular="{TemplateBinding AreVerticalSnapPointsRegular}"
AreHorizontalSnapPointsRegular="{TemplateBinding AreHorizontalSnapPointsRegular}"
ItemsPanel="{TemplateBinding ItemsPanel}" /> ItemsPanel="{TemplateBinding ItemsPanel}" />
</ScrollViewer> </ScrollViewer>
</Border> </Border>

Loading…
Cancel
Save