From 14d429ec4eca994998c995753bcf2a45f5ed914b Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Wed, 30 Nov 2022 00:18:48 +0100 Subject: [PATCH] Added ItemsControl.GetRealizedContainers(). --- src/Avalonia.Controls/ItemsControl.cs | 5 ++ src/Avalonia.Controls/MenuItem.cs | 11 +--- .../Presenters/ItemsPresenter.cs | 10 ++++ .../Primitives/SelectingItemsControl.cs | 59 +++++++++---------- src/Avalonia.Controls/VirtualizingPanel.cs | 6 ++ .../VirtualizingStackPanel.cs | 6 ++ tests/Avalonia.LeakTests/ControlTests.cs | 27 ++++----- 7 files changed, 69 insertions(+), 55 deletions(-) diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index c4356e2967..e56cad15b8 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -211,6 +211,11 @@ namespace Avalonia.Controls throw new NotImplementedException(); } + /// + /// Gets the currently realized containers. + /// + public IEnumerable GetRealizedContainers() => Presenter?.GetRealizedContainers() ?? Array.Empty(); + /// void IItemsPresenterHost.RegisterItemsPresenter(ItemsPresenter presenter) { diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index d134704b26..dd336974ca 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -328,16 +328,7 @@ namespace Avalonia.Controls } /// - IEnumerable IMenuElement.SubItems - { - get - { - throw new NotImplementedException(); - ////return ItemContainerGenerator.Containers - //// .Select(x => x.ContainerControl) - //// .OfType(); - } - } + IEnumerable IMenuElement.SubItems => GetRealizedContainers().OfType(); /// /// Opens the submenu. diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs index 5f90c264d7..6f27349cc1 100644 --- a/src/Avalonia.Controls/Presenters/ItemsPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ItemsPresenter.cs @@ -1,5 +1,8 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Diagnostics; +using System.Reflection; namespace Avalonia.Controls.Presenters { @@ -109,6 +112,13 @@ namespace Avalonia.Controls.Presenters return index >= 0 && index < Panel?.Children.Count ? Panel.Children[index] : null; } + internal IEnumerable? GetRealizedContainers() + { + if (Panel is VirtualizingPanel v) + return v.GetRealizedContainers(); + return Panel?.Children; + } + internal int IndexFromContainer(Control container) { if (Panel is VirtualizingPanel v) diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs index 1503da1322..a49705d754 100644 --- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs +++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs @@ -507,45 +507,44 @@ namespace Avalonia.Controls.Primitives protected override void OnTextInput(TextInputEventArgs e) { - throw new NotImplementedException(); - ////if (!e.Handled) - ////{ - //// if (!IsTextSearchEnabled) - //// return; + if (!e.Handled) + { + if (!IsTextSearchEnabled) + return; - //// StopTextSearchTimer(); + StopTextSearchTimer(); - //// _textSearchTerm += e.Text; + _textSearchTerm += e.Text; - //// bool Match(ItemContainerInfo info) - //// { - //// if (info.ContainerControl is AvaloniaObject ao && ao.IsSet(TextSearch.TextProperty)) - //// { - //// var searchText = ao.GetValue(TextSearch.TextProperty); + bool Match(Control container) + { + if (container is AvaloniaObject ao && ao.IsSet(TextSearch.TextProperty)) + { + var searchText = ao.GetValue(TextSearch.TextProperty); - //// if (searchText?.StartsWith(_textSearchTerm, StringComparison.OrdinalIgnoreCase) == true) - //// { - //// return true; - //// } - //// } + if (searchText?.StartsWith(_textSearchTerm, StringComparison.OrdinalIgnoreCase) == true) + { + return true; + } + } - //// return info.ContainerControl is IContentControl control && - //// control.Content?.ToString()?.StartsWith(_textSearchTerm, StringComparison.OrdinalIgnoreCase) == true; - //// } - - //// var info = ItemContainerGenerator?.Containers.FirstOrDefault(Match); + return container is IContentControl control && + control.Content?.ToString()?.StartsWith(_textSearchTerm, StringComparison.OrdinalIgnoreCase) == true; + } - //// if (info != null) - //// { - //// SelectedIndex = info.Index; - //// } + var container = GetRealizedContainers().FirstOrDefault(Match); - //// StartTextSearchTimer(); + if (container != null) + { + SelectedIndex = IndexFromContainer(container); + } - //// e.Handled = true; - ////} + StartTextSearchTimer(); + + e.Handled = true; + } - ////base.OnTextInput(e); + base.OnTextInput(e); } protected override void OnKeyDown(KeyEventArgs e) diff --git a/src/Avalonia.Controls/VirtualizingPanel.cs b/src/Avalonia.Controls/VirtualizingPanel.cs index 87c630658f..0b7a183728 100644 --- a/src/Avalonia.Controls/VirtualizingPanel.cs +++ b/src/Avalonia.Controls/VirtualizingPanel.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics.CodeAnalysis; using Avalonia.Controls.Utils; @@ -62,6 +63,11 @@ namespace Avalonia.Controls /// protected internal abstract int IndexFromContainer(Control container); + /// + /// Gets the currently realized containers. + /// + protected internal abstract IEnumerable? GetRealizedContainers(); + /// /// Gets the next control in the specified direction. /// diff --git a/src/Avalonia.Controls/VirtualizingStackPanel.cs b/src/Avalonia.Controls/VirtualizingStackPanel.cs index 1016a0af59..76cbf94f09 100644 --- a/src/Avalonia.Controls/VirtualizingStackPanel.cs +++ b/src/Avalonia.Controls/VirtualizingStackPanel.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; +using System.Linq; using Avalonia.Controls.Utils; using Avalonia.Input; using Avalonia.Layout; @@ -228,6 +229,11 @@ namespace Avalonia.Controls return ScrollIntoView(toIndex); } + protected internal override IEnumerable? GetRealizedContainers() + { + return _realizedElements?.Elements.Where(x => x is not null)!; + } + protected internal override Control? ContainerFromIndex(int index) => _realizedElements?.GetElement(index); protected internal override int IndexFromContainer(Control container) => _realizedElements?.GetIndex(container) ?? -1; diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index f46ad44684..4433e25c5a 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -361,8 +361,7 @@ namespace Avalonia.LeakTests // Do a layout and make sure that TreeViewItems get realized. window.LayoutManager.ExecuteInitialLayoutPass(); - throw new NotImplementedException(); - ////Assert.Single(target.ItemContainerGenerator.Containers); + Assert.Single(target.GetRealizedContainers()); // Clear the content and ensure the TreeView is removed. window.Content = null; @@ -757,22 +756,20 @@ namespace Avalonia.LeakTests window.Show(); window.LayoutManager.ExecuteInitialLayoutPass(); - throw new NotImplementedException(); + void AssertInitialItemState() + { + var item0 = (ListBoxItem)lb.GetRealizedContainers().First(); + var canvas0 = (Canvas)item0.Presenter.Child; + Assert.Equal("foo", canvas0.Tag); + } - ////void AssertInitialItemState() - ////{ - //// var item0 = (ListBoxItem)lb.ItemContainerGenerator.Containers.First().ContainerControl; - //// var canvas0 = (Canvas)item0.Presenter.Child; - //// Assert.Equal("foo", canvas0.Tag); - ////} - - ////Assert.Equal(10, lb.ItemContainerGenerator.Containers.Count()); - ////AssertInitialItemState(); + Assert.Equal(10, lb.GetRealizedContainers().Count()); + AssertInitialItemState(); - ////items.Clear(); - ////window.LayoutManager.ExecuteLayoutPass(); + items.Clear(); + window.LayoutManager.ExecuteLayoutPass(); - ////Assert.Empty(lb.ItemContainerGenerator.Containers); + Assert.Empty(lb.GetRealizedContainers()); // Process all Loaded events to free control reference(s) Dispatcher.UIThread.RunJobs(DispatcherPriority.Loaded);