-
Notifications
You must be signed in to change notification settings - Fork 971
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net5.0 System.Windows.Forms.ListView no longer displays LargeIcon #4169
Comments
Thanks for looking at it RussKie, Regards, John. |
I've tested the repro against the official releases: https://dotnet.microsoft.com/download/dotnet/5.0. The issue doesn't repro against 5.0.100-preview.8.20417.9, but repros against 5.0.100-rc.1.20452.10. |
It appears the regressions is caused by 03db3fb (#3601). Reverting the change restores the functionality: diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs
index 1fc7c4a22..5de24a63e 100644
--- a/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs
+++ b/src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs
@@ -1257,12 +1257,7 @@ namespace System.Windows.Forms
return;
}
- var previousHandle = User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.NORMAL, value is null ? IntPtr.Zero : value.CreateUniqueHandle());
- if (previousHandle != IntPtr.Zero)
- {
- var result = ComCtl32.ImageList.Destroy(previousHandle);
- Debug.Assert(result.IsTrue());
- }
+ User32.SendMessageW(this, (User32.WM)LVM.SETIMAGELIST, (IntPtr)LVSIL.NORMAL, value is null ? IntPtr.Zero : value.Handle);
if (AutoArrange && !listViewState1[LISTVIEWSTATE1_disposingImageLists])
{ @weltkante what do you think? I added a repro in https://github.com/RussKie/winforms/tree/fix_4169 |
@weltkante what I think is now happening - we have a total disconnect between a managed imagelist, to which a user assigns images, and an unmanaged imagelist that we assign via |
That was the point of the PR, because the sharing of image lists was totally broken (obviously I missed the usecase in this issue, sorry for that). Copying the ImageList seemed the sane way since it avoids you having to figure out the ownership rules of the native controls (which are not entirely documented, and WinForms was getting them wrong all the time). I guess to support adding images after assigning the ImageList there are two options:
Both are significant work, so the second option has the advantage of being more optimized (no copying of ImageLists), however can only be done by someone who is able to look at the native controls code. If you do not have the resources for that I can offer to make a draft PR for the subscriber model. Let me know what you think (or if you have any other ideas how to implement it properly). Until then the workaround is to clear/reassign the ImageList in user code when you change the images after the initial assignment. PS: I recommend strongly against reverting and going back to the previous implementation, it was totally broken and not restricted to multithreaded scenarios. While the multithreading initated the investigation, afterwards we noticed several other bugs also getting fixed through this PR. |
Unfortunately, we're in a situation right now where migration could well be blocked. If users of the ListView need to use the LargeIcon feature they have no way to do so - with no viable workaround and no real alternative. We also don't know if there are other ImageList scenarios that may also be broken. Our hunch is that there may well be. It's too bad we can't get it into the GA release, but we'll be getting something in for the first servicing instance. The best course of action right now is to get our users into a known state - even if this state is broken, it's the state they've been in for the past 20 years. So we should revert the change that causes the problem and get a feature request filed in the repo ASAP to take a deeper look at scenarios around ImageLists. We'll be syncing internally with the comctl32.dll team to understand what they're doing and how we might be able to predictably work with their ownership model (if that's even possible). I'd rather take the time to do the feature right than to rush something through that has the potential to create bigger problems than it solves. As part of implementing the 6.0 feature we should certainly leverage the work done in #3601. |
I stated a workaround above, the image list property can be cleared and reassigned. However I aknowledge your choice of keeping the old bugs over trading them for new bugs.
It has been causing significant pain in your own test infrastructure though, so I imagine the cost of reverting is higher than you expect, but its your decision to make. You may also need to revert more than just that single PR, since later PRs added stricter error checking, which will now fail when you reintroduce the ownership handling bugs in the WinForms implementation. Reverting probably needs to repriorize #3531 because it will be possible to trigger that again from applications, and also will make the unit tests flaky again (#3358), so you might not want to take your time and still look for an intermediate solution. |
If we'd discovered the issue while working on #3601, we wouldn't have taken it in the current shape. Unfortunately we're out of time to make additional explorations for .NET 5.0.
I suppose we can explore reassigning the native imagelist every time the managed one changes. Again, it isn't something we would do for .NET 5.0. |
@jcddcjjcd as a workaround until we implement a fix you need unbind and rebind the imagelist after it changed, e.g. the following makes your sample work again: mfref.SafeInvoke(delegate
{
lvwImages.EndUpdate();
lvwImages.ResumeLayout();
TimeSpan ts = DateTime.Now.Subtract(StartTime);
string elapsedTime = String.Format("{0:00}h {1:00}m {2:00}s.{3:000}ms",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds);
//Debug.WriteLine(elapsedTime, "RunTime");
+ lvwImages.LargeImageList = null;
+ lvwImages.LargeImageList = largeThumbnailList;
lvwImages.Update();
Cursor = Cursors.Default;
}, false); |
RussKie. |
The bug occours also the SmallImageList. |
The issue is with the |
Changes in `ImageList` ownership model in dotnet#3601 means that very are now two instances of imagelists - one instance is tracked by Windows Forms (i.e. managed) side, and another one tracked by the underlying Win32 (unmanaged) side. This was done due to an observed ownership disconnect between the managed and unmanged code, that led to situations where the unmanaged code would effectively destroy and instance of an imagelist, which the managed code was oblivious to. However with the above change changes to images in an imagelist on the managed side, i.e. a user adding or replacing an image in the imagelist, would not be reflected in the imagelist on the unmanaged side, and thus would not be reflected in the UI (which is drawn by the Win32). The fix reuses the established infrastructure that notifies the managed imagelist implementation of changes to the images collection, and once a notification of a chance is received, the unmanaged imagelist is re-created, thus ensuring the UI has all the correct images to display. Fixes dotnet#4169
RussKie. lvwImages.Items.AddRange(listOfItems.ToArray()); is intermittently crashing with large selections of 1500 and larger mainly and I think it is related to current bug in ListView. Regards, John. |
I don't think this is related or will be fixed by the PR, the bug was caused by not updating the image list after initial creation, "not updating" something shouldn't be crashing. You may just be exhausting some memory limits by adding a huge amount of images? For fixing the ImageList ownership issues the current implementation copies ImageLists which does increase the memory usage in .NET Core (which I noted in the PR #3601), so code that runs close to the limits on Desktop Framework may start to fail on .NET Core due to running out of memory. That may not be solvable unless someone takes the time to figure out how the native controls work and can implement an optimized version of the ImageList handling. In either case its probably a separate issue, if you have a repro that works on Desktop and fails on Core it would probably be appreciated if you open an issue to keep track of the problem. |
Similar (same?) issue reported on Feedback hub here , but affecting Listview in Details mode |
Verified the issue with .NET 6.0.100-alpha.1.20573.25 and .NET 5.0.200-preview.20573.23, the image can be load successfully for now. see below GIF. |
Revert "Explicit ImageList ownership management. (dotnet#3601)" This reverts commit 03db3fb. Revert "Fix `ListView` no longer displays images (dotnet#4184)" This reverts commit d0608e7. We have observed an instability of tests under stress (and reasonably high degree of concurrency) presumably caused by ImageList lifetime handling (notably dotnet#3358). The changes introduced in dotnet#3601 have helped with tests stability, however resulted in a number of regressions, such as dotnet#4169 and dotnet#4275. Restore the original implementation given it worked reasonably well for the past so many years.
Verified this issue in .Net SDK 5.0.101 build, this issue is fixed. |
Revert "Explicit ImageList ownership management. (#3601)" This reverts commit 03db3fb. Revert "Fix `ListView` no longer displays images (#4184)" This reverts commit d0608e7. We have observed an instability of tests under stress (and reasonably high degree of concurrency) presumably caused by ImageList lifetime handling (notably #3358). The changes introduced in #3601 have helped with tests stability, however resulted in a number of regressions, such as #4169 and #4275. Restore the original implementation given it worked reasonably well for the past so many years.
Revert "Explicit ImageList ownership management. (dotnet#3601)" This reverts commit 03db3fb. Revert "Fix `ListView` no longer displays images (dotnet#4184)" This reverts commit d0608e7. We have observed an instability of tests under stress (and reasonably high degree of concurrency) presumably caused by ImageList lifetime handling (notably dotnet#3358). The changes introduced in dotnet#3601 have helped with tests stability, however resulted in a number of regressions, such as dotnet#4169 and dotnet#4275. Restore the original implementation given it worked reasonably well for the past so many years. (cherry picked from commit b0ee5da)
Revert "Explicit ImageList ownership management. (#3601)" This reverts commit 03db3fb. Revert "Fix `ListView` no longer displays images (#4184)" This reverts commit d0608e7. We have observed an instability of tests under stress (and reasonably high degree of concurrency) presumably caused by ImageList lifetime handling (notably #3358). The changes introduced in #3601 have helped with tests stability, however resulted in a number of regressions, such as #4169 and #4275. Restore the original implementation given it worked reasonably well for the past so many years. (cherry picked from commit b0ee5da)
Sample code below works with a ListView in dotnet 4.8 and netcore3.1 but not in netcore5.0
The form for code below is simply a button and a ListView displaying in LargeIcon mode:
The checkboxes and text labels do work, just the image missing.
ownerDraw does work using the same bitmap from LargeImageList.
TestListView Core.zip
The text was updated successfully, but these errors were encountered: