mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-18 14:37:19 +08:00
194 lines
6.6 KiB
C#
194 lines
6.6 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.Reflection;
|
|
using AtomUI.Controls.Data;
|
|
using AtomUI.Controls.Utils;
|
|
using Avalonia.Controls;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using AtomListView = AtomUI.Desktop.Controls.ListView;
|
|
using AtomPagination = AtomUI.Desktop.Controls.Pagination;
|
|
|
|
namespace AtomUI.Desktop.Controls.Tests.ListView;
|
|
|
|
public class ListViewStateTests
|
|
{
|
|
static ListViewStateTests()
|
|
{
|
|
AvaloniaTestApp.EnsureInitialized();
|
|
}
|
|
|
|
[Fact]
|
|
public void ItemsSource_Wrap_Does_Not_Install_Default_Filter_Without_Active_Filtering()
|
|
{
|
|
var listView = new AtomListView
|
|
{
|
|
ItemsSource = CreateItems("alpha", "beta")
|
|
};
|
|
|
|
var collectionView = listView.ItemsSource.ShouldBeAssignableTo<IListCollectionView>();
|
|
|
|
collectionView.Filter.ShouldBeNull(
|
|
"a ListView with no filter conditions should not force ListCollectionView into the local filtering path.");
|
|
collectionView.FilterDescriptions.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Default_Filter_Callback_Is_Attached_Only_While_Filter_Conditions_Are_Active()
|
|
{
|
|
var listView = new AtomListView
|
|
{
|
|
ItemsSource = CreateItems("alpha", "beta"),
|
|
Filter = ValueFilterFactory.BuildFilter(ValueFilterMode.Contains)
|
|
};
|
|
var collectionView = listView.ItemsSource.ShouldBeAssignableTo<IListCollectionView>();
|
|
|
|
listView.FilterValue = "alpha";
|
|
|
|
collectionView.Filter.ShouldNotBeNull(
|
|
"ListView needs its default callback only when FilterDescriptions should drive the collection view.");
|
|
collectionView.FilterDescriptions.Count.ShouldBe(1);
|
|
|
|
listView.FilterValue = null;
|
|
|
|
collectionView.Filter.ShouldBeNull(
|
|
"the default callback should be removed when ListView no longer owns active filter conditions.");
|
|
collectionView.FilterDescriptions.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Bottom_Pagination_State_Tracks_Collection_View_Changes()
|
|
{
|
|
var items = new ObservableCollection<ListItemData>(CreateItems("alpha", "beta"));
|
|
var pagination = new AtomPagination();
|
|
var listView = new AtomListView
|
|
{
|
|
PageSize = 10,
|
|
ItemsSource = items,
|
|
BottomPagination = pagination
|
|
};
|
|
|
|
pagination.Total.ShouldBe(2);
|
|
pagination.PageSize.ShouldBe(10);
|
|
pagination.CurrentPage.ShouldBe(1);
|
|
|
|
items.Add(new ListItemData { Content = "gamma" });
|
|
|
|
listView.TotalItemCount.ShouldBe(3);
|
|
pagination.Total.ShouldBe(3);
|
|
pagination.PageSize.ShouldBe(10);
|
|
pagination.CurrentPage.ShouldBe(1);
|
|
}
|
|
|
|
[Fact]
|
|
public void Pagination_Visibility_Does_Not_Override_Pagination_Motion_State()
|
|
{
|
|
var pagination = new AtomPagination();
|
|
var listView = new AtomListView
|
|
{
|
|
IsMotionEnabled = true,
|
|
ItemsSource = CreateItems("alpha", "beta"),
|
|
BottomPagination = pagination,
|
|
PaginationVisibility = ListPaginationVisibility.None
|
|
};
|
|
|
|
pagination.IsVisible.ShouldBeFalse();
|
|
pagination.IsMotionEnabled.ShouldBeTrue(
|
|
"PaginationVisibility controls visibility only and must not be relayed into IsMotionEnabled.");
|
|
|
|
listView.PaginationVisibility = ListPaginationVisibility.Bottom;
|
|
|
|
pagination.IsVisible.ShouldBeTrue();
|
|
pagination.IsMotionEnabled.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void ItemsSource_Replacement_Uses_The_New_Entry_Selection_Lifecycle()
|
|
{
|
|
var listView = new AtomListView
|
|
{
|
|
ItemsSource = CreateItems("alpha", "beta", "gamma"),
|
|
SelectionMode = SelectionMode.AlwaysSelected
|
|
};
|
|
|
|
listView.SelectedIndex = 1;
|
|
listView.ItemsSource = CreateItems("delta", "epsilon", "zeta");
|
|
listView.SelectedIndex = 2;
|
|
|
|
listView.SelectedIndex.ShouldBe(2,
|
|
"the new source owns a fresh occurrence identity lifecycle.");
|
|
}
|
|
|
|
[Fact]
|
|
public void Removing_Selected_Entry_Publishes_Deselection_With_Old_Item()
|
|
{
|
|
var first = new ListItemData { Content = "first" };
|
|
var second = new ListItemData { Content = "second" };
|
|
var source = new ObservableCollection<ListItemData> { first, second };
|
|
var listView = new AtomListView
|
|
{
|
|
ItemsSource = source,
|
|
SelectionMode = SelectionMode.Multiple
|
|
};
|
|
ListViewSelectionChangedEventArgs? change = null;
|
|
listView.SelectionChanged += (_, args) =>
|
|
{
|
|
if (args.DeselectedItems.Count > 0)
|
|
{
|
|
change = args;
|
|
}
|
|
};
|
|
|
|
listView.Selection.Select(1);
|
|
source.RemoveAt(1);
|
|
|
|
change.ShouldNotBeNull();
|
|
change!.DeselectedItems.ShouldBe([second]);
|
|
listView.SelectedItems.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Virtualizing_Context_Tolerates_Duplicate_Recycled_Index()
|
|
{
|
|
var listView = new AtomListView();
|
|
var firstContainer = new AtomUI.Desktop.Controls.ListViewItem();
|
|
var secondContainer = new AtomUI.Desktop.Controls.ListViewItem();
|
|
var itemData = new ListItemData { Content = "item" };
|
|
|
|
PrepareContainerForItem(listView, firstContainer, itemData, 5);
|
|
PrepareContainerForItem(listView, secondContainer, itemData, 5);
|
|
|
|
ClearContainerForItem(listView, firstContainer);
|
|
Should.NotThrow(() => ClearContainerForItem(listView, secondContainer),
|
|
"virtualized collection mutations can recycle more than one stale container for the same index before one is restored.");
|
|
}
|
|
|
|
private static ListItemData[] CreateItems(params string[] values)
|
|
{
|
|
return values.Select(value => new ListItemData { Content = value }).ToArray();
|
|
}
|
|
|
|
private static void PrepareContainerForItem(
|
|
AtomListView listView,
|
|
AtomUI.Desktop.Controls.ListViewItem container,
|
|
object item,
|
|
int index)
|
|
{
|
|
var method = typeof(AtomListView).GetMethod(
|
|
"PrepareContainerForItemOverride",
|
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
method.ShouldNotBeNull();
|
|
method.Invoke(listView, [container, item, index]);
|
|
}
|
|
|
|
private static void ClearContainerForItem(
|
|
AtomListView listView,
|
|
AtomUI.Desktop.Controls.ListViewItem container)
|
|
{
|
|
var method = typeof(AtomListView).GetMethod(
|
|
"ClearContainerForItemOverride",
|
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
|
method.ShouldNotBeNull();
|
|
method.Invoke(listView, [container]);
|
|
}
|
|
}
|