Browse Source

Make sure ItemsPresenter is updated before selection change.

Having a separate subscription to `Items.CollectionChanged` in both `ItemsControl` and `ItemsPresenter` meant that the `ItemsPresenter` sometimes doesn't update itself in time for a selection change, resulting in #3148. Make `ItemsControl` trigger `ItemsPresenter.ItemsChanged` rather than both controls listening to the event separately.
pull/3177/head
Steven Kirk 7 years ago
parent
commit
4f41a70455
  1. 6
      src/Avalonia.Controls/ItemsControl.cs
  2. 4
      src/Avalonia.Controls/Presenters/IItemsPresenter.cs
  3. 15
      src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
  4. 17
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

6
src/Avalonia.Controls/ItemsControl.cs

@ -356,6 +356,7 @@ namespace Avalonia.Controls
var oldValue = e.OldValue as IEnumerable;
var newValue = e.NewValue as IEnumerable;
Presenter?.ItemsChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
UpdateItemCount();
RemoveControlItemsFromLogicalChildren(oldValue);
AddControlItemsToLogicalChildren(newValue);
@ -370,6 +371,9 @@ namespace Avalonia.Controls
/// <param name="e">The event args.</param>
protected virtual void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
UpdateItemCount();
Presenter?.ItemsChanged(e);
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
@ -381,8 +385,6 @@ namespace Avalonia.Controls
break;
}
UpdateItemCount();
var collection = sender as ICollection;
PseudoClasses.Set(":empty", collection == null || collection.Count == 0);
PseudoClasses.Set(":singleitem", collection != null && collection.Count == 1);

4
src/Avalonia.Controls/Presenters/IItemsPresenter.cs

@ -1,12 +1,16 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections.Specialized;
namespace Avalonia.Controls.Presenters
{
public interface IItemsPresenter : IPresenter
{
IPanel Panel { get; }
void ItemsChanged(NotifyCollectionChangedEventArgs e);
void ScrollIntoView(object item);
}
}

15
src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs

@ -63,7 +63,7 @@ namespace Avalonia.Controls.Presenters
_itemsSubscription?.Dispose();
_itemsSubscription = null;
if (_createdPanel && value is INotifyCollectionChanged incc)
if (!IsHosted && _createdPanel && value is INotifyCollectionChanged incc)
{
_itemsSubscription = incc.WeakSubscribe(ItemsCollectionChanged);
}
@ -130,6 +130,8 @@ namespace Avalonia.Controls.Presenters
private set;
}
protected bool IsHosted => TemplatedParent is IItemsPresenterHost;
/// <inheritdoc/>
public override sealed void ApplyTemplate()
{
@ -144,6 +146,15 @@ namespace Avalonia.Controls.Presenters
{
}
/// <inheritdoc/>
void IItemsPresenter.ItemsChanged(NotifyCollectionChangedEventArgs e)
{
if (Panel != null)
{
ItemsChanged(e);
}
}
/// <summary>
/// Creates the <see cref="ItemContainerGenerator"/> for the control.
/// </summary>
@ -215,7 +226,7 @@ namespace Avalonia.Controls.Presenters
_createdPanel = true;
if (_itemsSubscription == null && Items is INotifyCollectionChanged incc)
if (!IsHosted && _itemsSubscription == null && Items is INotifyCollectionChanged incc)
{
_itemsSubscription = incc.WeakSubscribe(ItemsCollectionChanged);
}

17
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -302,13 +302,24 @@ namespace Avalonia.Controls.Primitives
/// <inheritdoc/>
protected override void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
base.ItemsCollectionChanged(sender, e);
if (_updateCount > 0)
{
base.ItemsCollectionChanged(sender, e);
return;
}
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
_selection.ItemsInserted(e.NewStartingIndex, e.NewItems.Count);
break;
case NotifyCollectionChangedAction.Remove:
_selection.ItemsRemoved(e.OldStartingIndex, e.OldItems.Count);
break;
}
base.ItemsCollectionChanged(sender, e);
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
@ -318,14 +329,12 @@ namespace Avalonia.Controls.Primitives
}
else
{
_selection.ItemsInserted(e.NewStartingIndex, e.NewItems.Count);
UpdateSelectedItem(_selection.First(), false);
}
break;
case NotifyCollectionChangedAction.Remove:
_selection.ItemsRemoved(e.OldStartingIndex, e.OldItems.Count);
UpdateSelectedItem(_selection.First(), false);
ResetSelectedItems();
break;

Loading…
Cancel
Save