Browse Source

Don't detach from ScrollViewer when detached from visual tree

Fixes offset resetting when switching between tabs
pull/10803/head
Tom Edwards 3 years ago
parent
commit
87e2ed8107
  1. 27
      src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
  2. 29
      src/Avalonia.Controls/Primitives/ScrollBar.cs
  3. 7
      src/Avalonia.Controls/ScrollViewer.cs

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

@ -304,15 +304,23 @@ namespace Avalonia.Controls.Presenters
/// </remarks>
protected internal virtual void AttachToScrollViewer()
{
_ownerSubscriptions?.Dispose();
var owner = _owner = this.FindAncestorOfType<ScrollViewer>();
var owner = this.FindAncestorOfType<ScrollViewer>();
if (owner == null)
{
_owner = null;
_ownerSubscriptions?.Dispose();
_ownerSubscriptions = null;
return;
}
if (owner == _owner)
{
return;
}
_ownerSubscriptions?.Dispose();
var subscriptionDisposables = new IDisposable?[]
{
IfUnset(CanHorizontallyScrollProperty, p => Bind(p, owner.GetObservable(ScrollViewer.HorizontalScrollBarVisibilityProperty, NotDisabled), Data.BindingPriority.Template)),
@ -322,19 +330,12 @@ namespace Avalonia.Controls.Presenters
IfUnset(ContentProperty, p => Bind(p, owner.GetBindingObservable(ContentProperty), Data.BindingPriority.Template)),
}.Where(d => d != null).Cast<IDisposable>().ToArray();
_owner = owner;
_ownerSubscriptions = new CompositeDisposable(subscriptionDisposables);
static bool NotDisabled(ScrollBarVisibility v) => v != ScrollBarVisibility.Disabled;
IDisposable? IfUnset<T>(T property, Func<T, IDisposable> func) where T : AvaloniaProperty => GetValueStore().IsSet(property) ? null : func(property);
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_ownerSubscriptions?.Dispose();
_owner = null;
base.OnDetachedFromVisualTree(e);
IDisposable? IfUnset<T>(T property, Func<T, IDisposable> func) where T : AvaloniaProperty => IsSet(property) ? null : func(property);
}
/// <inheritdoc/>
@ -708,7 +709,7 @@ namespace Avalonia.Controls.Presenters
}
CoerceValue(OffsetProperty);
}
else if (change.Property == ViewportProperty && _owner != null)
else if (change.Property == ViewportProperty)
{
if (_owner != null)
{

29
src/Avalonia.Controls/Primitives/ScrollBar.cs

@ -202,15 +202,23 @@ namespace Avalonia.Controls.Primitives
/// </remarks>
protected internal virtual void AttachToScrollViewer()
{
_ownerSubscriptions?.Dispose();
var owner = _owner = this.FindAncestorOfType<ScrollViewer>();
var owner = this.FindAncestorOfType<ScrollViewer>();
if (owner == null)
{
_owner = null;
_ownerSubscriptions?.Dispose();
_ownerSubscriptions = null;
return;
}
if (owner == _owner)
{
return;
}
_ownerSubscriptions?.Dispose();
var visibilitySource = Orientation == Orientation.Horizontal ? ScrollViewer.HorizontalScrollBarVisibilityProperty : ScrollViewer.VerticalScrollBarVisibilityProperty;
var subscriptionDisposables = new IDisposable?[]
@ -224,21 +232,15 @@ namespace Avalonia.Controls.Primitives
IfUnset(SmallChangeProperty, p => Bind(p, owner.GetObservable(ScrollViewer.SmallChangeProperty).Select(ExtractOrdinate), BindingPriority.Template))
}.Where(d => d != null).Cast<IDisposable>().ToArray();
_owner = owner;
_ownerSubscriptions = new CompositeDisposable(subscriptionDisposables);
IDisposable? IfUnset<T>(T property, Func<T, IDisposable> func) where T : AvaloniaProperty => GetValueStore().IsSet(property) ? null : func(property);
IDisposable? IfUnset<T>(T property, Func<T, IDisposable> func) where T : AvaloniaProperty => IsSet(property) ? null : func(property);
}
private double ExtractOrdinate(Vector v) => Orientation == Orientation.Horizontal ? v.X : v.Y;
private double ExtractOrdinate(Size v) => Orientation == Orientation.Horizontal ? v.Width : v.Height;
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_ownerSubscriptions?.Dispose();
_owner = null;
base.OnDetachedFromVisualTree(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.PageUp)
@ -260,7 +262,10 @@ namespace Avalonia.Controls.Primitives
if (change.Property == OrientationProperty)
{
UpdatePseudoClasses(change.GetNewValue<Orientation>());
AttachToScrollViewer(); // there's no way to manually refresh bindings, so reapply them
if (IsAttachedToVisualTree)
{
AttachToScrollViewer(); // there's no way to manually refresh bindings, so reapply them
}
}
else if (change.Property == AllowAutoHideProperty)
{

7
src/Avalonia.Controls/ScrollViewer.cs

@ -660,8 +660,11 @@ namespace Avalonia.Controls
private void CalculatedPropertiesChanged()
{
var newMaximum = ScrollBarMaximum;
RaisePropertyChanged(ScrollBarMaximumProperty, _oldMaximum, newMaximum);
_oldMaximum = newMaximum;
if (newMaximum != _oldMaximum)
{
RaisePropertyChanged(ScrollBarMaximumProperty, _oldMaximum, newMaximum);
_oldMaximum = newMaximum;
}
if (_logicalScrollable?.IsLogicalScrollEnabled == true)
{

Loading…
Cancel
Save