- 
                Notifications
    
You must be signed in to change notification settings  - Fork 1.1k
 
Description
.NET version
9.0
Did it work in .NET Framework?
Not tested/verified
Did it work in any of the earlier releases of .NET Core or .NET 5+?
I saw in the source code a dependency to OsVersion.IsWindows8OrGreater()
Issue description
I am using a ListView with VirtualMode = true to display a list a few thousands items.
When the ListView is destroyed, the OnRetrieveVirtualItem() is called for each index (even never retrieved ones).
This kills somehow the performance of the control.
Analyses as far I saw it in the debugger:
ListView overrides the internal bool SupportsUiaProviders => true;
First problem: I cannot change that because it's internal.
WM_DESTROY invokes on the Control class
private void WmDestroy(ref Message m)
{
	if (!RecreatingHandle && !Disposing && !IsDisposed && GetState(States.TrackingMouseEvent))
	{
		OnMouseLeave(EventArgs.Empty);
		UnhookMouseEvent();
	}
	if (SupportsUiaProviders)  // <--- THIS RETURNS TRUE
	{
		ReleaseUiaProvider(HWNDInternal);  // <--- THIS GETS CALLED
	}
	OnHandleDestroyed(EventArgs.Empty);
	if (!Disposing)
	{
		if (!RecreatingHandle)
		{
			SetState(States.Created, value: false);
		}
	}
	else
	{
		SetState(States.Visible, value: false);
	}
	DefWndProc(ref m);
}
This invokes on the ListView class
internal override bool SupportsUiaProviders => true;
internal override void ReleaseUiaProvider(HWND handle)
{
	if (!OsVersion.IsWindows8OrGreater())
	{
		return;
	}
	for (int i = 0; i < Items.Count; i++)  // <--- THIS ITERATES OVER ALL INDICES IN THE VIRTUAL LIST VIEW
	{
		Items.GetItemByIndex(i)?.ReleaseUiaProvider(); // <--- THIS INVOKES OnRetrieveVirtualItem(e)
	}
	if (_defaultGroup != null)
	{
		DefaultGroup.ReleaseUiaProvider();
	}
	foreach (ListViewGroup group in Groups)
	{
		group.ReleaseUiaProvider();
	}
	foreach (ColumnHeader column in Columns)
	{
		column.ReleaseUiaProvider();
	}
	base.ReleaseUiaProvider(handle);
}
After this super expensive retrieval, ListViewItem then does nothing
internal void ReleaseUiaProvider()
{
	if (!IsAccessibilityObjectCreated)  // <--- RETURNS FALSE
	{
		return;
	}
	if (OsVersion.IsWindows8OrGreater())
	{
		if (_accessibilityObject is ListViewItemBaseAccessibleObject listViewItemBaseAccessibleObject)
		{
			listViewItemBaseAccessibleObject.ReleaseChildUiaProviders();
		}
		PInvoke.UiaDisconnectProvider(_accessibilityObject, skipOSCheck: true);
	}
	_accessibilityObject = null;
}
Possible Resolutions
- Make SupportsUiaProviders protected overrideable.
 - Move the test 
if (!IsAccessibilityObjectCreated)higher up in the call hierachy. - Invoke the 
ReleaseUiaProvider()only for really created ListViewItems. 
Disclaimer
I'm not profient with UI Automation, so I do not know, what a proper implementation should excatly look like.
In my case I do not use this feature explicitly.
Steps to reproduce
An example is difficult to post.
Please see the analysis above.