diff --git a/src/System.Windows.Forms/src/Resources/SR.resx b/src/System.Windows.Forms/src/Resources/SR.resx index 30ef02209f0..eb3463bfcd6 100644 --- a/src/System.Windows.Forms/src/Resources/SR.resx +++ b/src/System.Windows.Forms/src/Resources/SR.resx @@ -4018,7 +4018,7 @@ Stack trace where the illegal operation occurred was: Occurs whenever the state of a virtual item is changed. - Sets the count of the item collection when the ListView is in virtual mode. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. Value of '{1}' is not valid for '{0}'. {0} should be greater than or equal to 0. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf index 473b134644c..3dcda2bf3e2 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.cs.xlf @@ -6855,8 +6855,8 @@ Trasování zásobníku, kde došlo k neplatné operaci: - Sets the count of the item collection when the ListView is in virtual mode. - Nastaví počet pro kolekci položek v případě, že je vlastnost ListView ve virtuálním režimu. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + Nastaví počet pro kolekci položek v případě, že je vlastnost ListView ve virtuálním režimu. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf index 858d6516ea7..c4ad1eb979d 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.de.xlf @@ -6855,8 +6855,8 @@ Stapelüberwachung, in der der unzulässige Vorgang auftrat: - Sets the count of the item collection when the ListView is in virtual mode. - Legt die Anzahl der Elemente für die Elementesammlung fest, wenn sich die ListView im virtuellen Modus befindet. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + Legt die Anzahl der Elemente für die Elementesammlung fest, wenn sich die ListView im virtuellen Modus befindet. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf index 9b15f44997c..4b0c7cb6206 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.es.xlf @@ -6855,8 +6855,8 @@ El seguimiento de la pila donde tuvo lugar la operación no válida fue: - Sets the count of the item collection when the ListView is in virtual mode. - Establece el recuento de la colección de elementos cuando ListView está en modo virtual. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + Establece el recuento de la colección de elementos cuando ListView está en modo virtual. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf index a0aa00d21e8..295238d61de 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.fr.xlf @@ -6855,8 +6855,8 @@ Cette opération non conforme s'est produite sur la trace de la pile : - Sets the count of the item collection when the ListView is in virtual mode. - Définit le nombre de la collection d'éléments lorsque le ListView est en mode virtuel. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + Définit le nombre de la collection d'éléments lorsque le ListView est en mode virtuel. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf index cd55b790fc5..46b84a15753 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.it.xlf @@ -6855,8 +6855,8 @@ Traccia dello stack da cui si è verificata l'operazione non valida: - Sets the count of the item collection when the ListView is in virtual mode. - Imposta il numero di elementi nella raccolta quando il controllo ListView è in modalità virtuale. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + Imposta il numero di elementi nella raccolta quando il controllo ListView è in modalità virtuale. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf index c3b80c6cb11..11a0511eb24 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.ja.xlf @@ -6855,8 +6855,8 @@ Stack trace where the illegal operation occurred was: - Sets the count of the item collection when the ListView is in virtual mode. - ListView が仮想モードであるときに、項目コレクションの数を設定します。 + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + ListView が仮想モードであるときに、項目コレクションの数を設定します。 diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf index eb0f49b7a4f..35710f7c3a9 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.ko.xlf @@ -6855,8 +6855,8 @@ Stack trace where the illegal operation occurred was: - Sets the count of the item collection when the ListView is in virtual mode. - ListView가 가상 모드에 있는 경우 항목 컬렉션의 개수를 설정합니다. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + ListView가 가상 모드에 있는 경우 항목 컬렉션의 개수를 설정합니다. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf index f4ae0ee4e09..1f8e1d1853d 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.pl.xlf @@ -6855,8 +6855,8 @@ Stos śledzenia, w którym wystąpiła zabroniona operacja: - Sets the count of the item collection when the ListView is in virtual mode. - Ustawia liczbę kolekcji elementów, gdy formant ListView jest w trybie wirtualnym. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + Ustawia liczbę kolekcji elementów, gdy formant ListView jest w trybie wirtualnym. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf index a1bfe7126db..35901777388 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.pt-BR.xlf @@ -6855,8 +6855,8 @@ Rastreamento de pilha em que a operação ilegal ocorreu: - Sets the count of the item collection when the ListView is in virtual mode. - Define a contagem de coleção de itens quando ListView está no modo virtual. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + Define a contagem de coleção de itens quando ListView está no modo virtual. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf index 5ec761c5c33..b5e9820ff21 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.ru.xlf @@ -6856,8 +6856,8 @@ Stack trace where the illegal operation occurred was: - Sets the count of the item collection when the ListView is in virtual mode. - Устанавливает счетчик коллекции элементов, когда ListView находится в виртуальном режиме. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + Устанавливает счетчик коллекции элементов, когда ListView находится в виртуальном режиме. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf index bfbb9ac5807..6d534d31821 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.tr.xlf @@ -6855,8 +6855,8 @@ Geçersiz işlemin gerçekleştiği yığın izi: - Sets the count of the item collection when the ListView is in virtual mode. - ListView sanal moddayken öğe koleksiyonu sayısını ayarlar. + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + ListView sanal moddayken öğe koleksiyonu sayısını ayarlar. diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf index 575cd4d96d2..e88497822f8 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hans.xlf @@ -6855,8 +6855,8 @@ Stack trace where the illegal operation occurred was: - Sets the count of the item collection when the ListView is in virtual mode. - 当 ListView 处于虚拟模式时,设置项集合的计数。 + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + 当 ListView 处于虚拟模式时,设置项集合的计数。 diff --git a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf index c7d30641156..5a9a29c2585 100644 --- a/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf +++ b/src/System.Windows.Forms/src/Resources/xlf/SR.zh-Hant.xlf @@ -6855,8 +6855,8 @@ Stack trace where the illegal operation occurred was: - Sets the count of the item collection when the ListView is in virtual mode. - 設定 ListView 處於虛擬模式時項目集合的計數。 + Sets the count of the item collection when the ListView is in virtual mode. If VirtualMode is set to true, and the VirtualListSize property is greater than 0, you must handle the RetrieveVirtualItem event providing valid items. + 設定 ListView 處於虛擬模式時項目集合的計數。 diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewItemCollection.IInnerList.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewItemCollection.IInnerList.cs index a41c43a54ae..1b99554316d 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewItemCollection.IInnerList.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewItemCollection.IInnerList.cs @@ -26,6 +26,20 @@ internal interface IInnerList ListViewItem Insert(int index, ListViewItem item); void Remove(ListViewItem item); void RemoveAt(int index); + ListViewItem? GetItemByIndex(int index) + { + ArgumentOutOfRangeException.ThrowIfNegative(index); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Count); + + try + { + return this[index]; + } + catch (InvalidOperationException) + { + return null; + } + } } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewItemCollection.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewItemCollection.cs index 1a4e21fbdca..dc4328e25cb 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewItemCollection.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewItemCollection.cs @@ -73,6 +73,14 @@ public virtual ListViewItem this[int index] } } + internal ListViewItem? GetItemByIndex(int index) + { + ArgumentOutOfRangeException.ThrowIfNegative(index); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, InnerList.Count); + + return InnerList.GetItemByIndex(index); + } + object? IList.this[int index] { get diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewNativeItemCollection.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewNativeItemCollection.cs index 6addbc83686..0d3e08a17b2 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewNativeItemCollection.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.ListViewNativeItemCollection.cs @@ -34,35 +34,7 @@ public int Count public ListViewItem this[int displayIndex] { - get - { - _owner.ApplyUpdateCachedItems(); - - if (_owner.VirtualMode) - { - // if we are showing virtual items, we need to get the item from the user - RetrieveVirtualItemEventArgs rVI = new(displayIndex); - _owner.OnRetrieveVirtualItem(rVI); - rVI.Item!.SetItemIndex(_owner, displayIndex); - return rVI.Item; - } - else - { - ArgumentOutOfRangeException.ThrowIfNegative(displayIndex); - ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(displayIndex, _owner._itemCount); - - if (_owner.IsHandleCreated && !_owner.ListViewHandleDestroyed) - { - _owner._listItemsTable.TryGetValue(DisplayIndexToID(displayIndex), out ListViewItem? item); - return item!; - } - else - { - Debug.Assert(_owner._listViewItems is not null, "listItemsArray is null, but the handle isn't created"); - return _owner._listViewItems[displayIndex]; - } - } - } + get => GetItemByIndexInternal(displayIndex, throwInVirtualMode: true)!; set { _owner.ApplyUpdateCachedItems(); @@ -84,6 +56,44 @@ public ListViewItem this[int displayIndex] } } + public ListViewItem? GetItemByIndex(int index) => + GetItemByIndexInternal(index, throwInVirtualMode: false); + + private ListViewItem? GetItemByIndexInternal(int index, [NotNullWhen(true)] bool throwInVirtualMode) + { + _owner.ApplyUpdateCachedItems(); + + if (_owner.VirtualMode) + { + // If we are showing virtual items, we need to get the item from the user. + RetrieveVirtualItemEventArgs rVI = new(index); + _owner.OnRetrieveVirtualItem(rVI); + if (rVI.Item is null) + { + return !throwInVirtualMode ? null : throw new InvalidOperationException(SR.ListViewVirtualItemRequired); + } + + rVI.Item.SetItemIndex(_owner, index); + return rVI.Item; + } + else + { + ArgumentOutOfRangeException.ThrowIfNegative(index); + ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _owner._itemCount); + + if (_owner.IsHandleCreated && !_owner.ListViewHandleDestroyed) + { + _owner._listItemsTable.TryGetValue(DisplayIndexToID(index), out ListViewItem? item); + return item!; + } + else + { + Debug.Assert(_owner._listViewItems is not null, "listItemsArray is null, but the handle isn't created"); + return _owner._listViewItems[index]; + } + } + } + public ListViewItem Add(ListViewItem value) { if (_owner.VirtualMode) diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs index 162d5f670b5..e30e268b1d5 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/Controls/ListView/ListView.cs @@ -5117,7 +5117,7 @@ internal override void ReleaseUiaProvider(HWND handle) for (int i = 0; i < Items.Count; i++) { - Items[i].ReleaseUiaProvider(); + Items.GetItemByIndex(i)?.ReleaseUiaProvider(); } if (_defaultGroup is not null) diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ListViewTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ListViewTests.cs index 8f7a607a0bd..c8d040503b9 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ListViewTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ListViewTests.cs @@ -5203,6 +5203,66 @@ public void ListView_AnnounceColumnHeader_WorksCorrectly(int x, int y, string ex Assert.True(listView.IsHandleCreated); } + public static TheoryData GetListViewItemTheoryData() => new() + { + { new("Item 1") }, + { null } + }; + + [WinFormsTheory] + [MemberData(nameof(GetListViewItemTheoryData))] + // Regression test for https://github.com/dotnet/winforms/issues/11663. + public void ListView_VirtualMode_ReleaseUiaProvider_Success(ListViewItem listItem) + { + using ListView listView = new() + { + VirtualMode = true, + VirtualListSize = 1 + }; + + listView.RetrieveVirtualItem += (s, e) => + { + e.Item = e.ItemIndex switch + { + 0 => listItem, + _ => throw new NotImplementedException() + }; + }; + + listView.AccessibilityObject.Should().NotBeNull(); + + Action action = () => listView.ReleaseUiaProvider(listView.InternalHandle); + action.Should().NotThrow(); + listView.IsAccessibilityObjectCreated.Should().BeFalse(); + listView.IsHandleCreated.Should().BeFalse(); + } + + [WinFormsFact] + public void ListView_VirtualMode_GetListViewItemAsExpected() + { + using ListView listView = new() + { + VirtualMode = true, + VirtualListSize = 2 + }; + + ListViewItem listItem1 = new("Item 1"); + ListViewItem listItem2 = null; + listView.RetrieveVirtualItem += (s, e) => + { + e.Item = e.ItemIndex switch + { + 0 => listItem1, + 1 => listItem2, + _ => throw new NotImplementedException() + }; + }; + listView.Items.GetItemByIndex(0).Should().Be(listView.Items[0]); + listView.Items.GetItemByIndex(1).Should().BeNull(); + Action action = () => listView.Items[1].ToString(); + action.Should().Throw(SR.ListViewVirtualItemRequired); + } + private class SubListViewAccessibleObject : ListView.ListViewAccessibleObject { internal string AnnouncedColumn { get; private set; }