Bug 23554 - (Android.Xamarin) ListView not recalculating size when ItemsSource updated
Summary: (Android.Xamarin) ListView not recalculating size when ItemsSource updated
Status: RESOLVED ANSWERED
Alias: None
Product: Forms
Classification: Xamarin
Component: Forms ()
Version: 1.2.3
Hardware: PC Windows
: Normal normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2014-10-02 13:00 UTC by Wayne Maurer
Modified: 2015-03-23 16:38 UTC (History)
7 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED ANSWERED

Description Wayne Maurer 2014-10-02 13:00:53 UTC
On Android, a ListView does not always display the contents of the collection its ItemsSource is set to. I suspect that the ListView is not recalculating its size when the ItemsSource is assigned a new collection.

I have a project that reproduces this project here:
https://github.com/wmaurer/XamarinFormsListViewRepro

The file to look at is HomePage.cs:
https://github.com/wmaurer/XamarinFormsListViewRepro/blob/master/XamarinFormsListViewRepro/XamarinFormsListViewRepro/HomePage.cs
Comment / uncomment lines 20, 23, or 26 to see the behaviour described in the code-comments.

In essence if the ListView ItemsSource is assigned a collection of size one in the constructor, then when it is assigned a new collection containing, say, 3 items, only the first of the 3 items is displayed.

The behaviour under Windows Phone is different. Under WP, all 3 items are displayed as expected.

A forum thread that supports this bug report is here:
http://forums.xamarin.com/discussion/25005/problem-with-listview-not-being-updated
Comment 1 Parmendra Kumar 2014-10-03 07:57:03 UTC
I have checked this issue and I am able to reproduce it. To reproduce this I have followed steps mentioned in the bug description.
I have checked this issue on device and emulator and getting the same behavior

Screencast:http://www.screencast.com/t/MJgVOF9WI
DebugLog:https://gist.github.com/Parmendrak/744236b766d3d0339228
ZipXamLog:https://gist.github.com/Parmendrak/e14c8181c12ffb20df78

Environment Info:
Microsoft Visual Studio Professional 2013
Version 12.0.30723.00 Update 3
Microsoft .NET Framework
Version 4.5.51641


Xamarin   3.6.262.0 (21b7dba8736246dfd10e3f19a92ed68f1b30abfd)
Visual Studio extension to enable development for Xamarin.iOS and Xamarin.Android.

Xamarin.Android   4.16.0.17 (2a7b68212b17c903160fbd8e0106babb299d1be3)
Visual Studio plugin to enable development for Xamarin.Android.

Xamarin.iOS   8.0.66.0 (3e201c8aa14879773f966f483329bcda49fd3a41)
Visual Studio extension to enable development for Xamarin.iOS.
Comment 2 Jason Smith [MSFT] 2014-10-03 08:13:15 UTC
Yep it turns out there is no way to fix this in a performant manner. In the future listviews will always measure to the same size and if you want a fixed size you will need to specify it.

Android and Windows Phone both are technically possible to perform this measurement on, but they make it so slow it would result in very long performance lags when you do it.
Comment 3 Wayne Maurer 2014-10-03 08:20:15 UTC
In this case, under Android, shouldn't the ListView FillAndExpand, i.e. take up the rest of the space of its parent StackLayout? That's what happens under Windows Phone.
Comment 4 Wayne Maurer 2014-10-07 14:02:41 UTC
@Jason, do you agree with this? According to my repro, the ListView VerticalLayout is set to FillAndExpand. That works correctly on Windows Phone, but it's not working on Android. I don't see why it the measurement can't be calculated on Android. As far as I'm concerned, the ListView on Android is not respecting the LayoutOption, and this is the core of the bug.
Comment 5 Charles Horan 2014-10-27 05:44:29 UTC
@Jason This bug is not simply about layout.  
I understand that you need to perform a layout calculation and prefer to do that as few times as possible.
Right now a ListView is not respecting the Horizontal and Vertical options set in the xaml.  Even if a ListView has zero elements in it's collection it should still take up the specified layout space.  Not doing so results in zero height list views.

Currently a does not recalculate it's layout when an item is added at a future point in time.

Case in point:  In my app I have a message center (in app messaging).  That message center is fed by a SignalR feed.  The listview that I use to display message summaries has an ItemsSource that starts out empty.  Over time as new messages comes in I add them to the ItemsSource.
With your current design the Listview that I use to display message summaries starts with a zero height(no items) and never recalculates it's layout as items are added. As a result the user never sees the messages.
This is a broken design.
If you either respected the layout options as put forth in the xaml, or recalculated as items are added/removed the users would see their messages.

Right now to work around this bug I have added a useless label showing the number of messages in the list to the page.  Updating the data binding on that label forces a layout recalculation of the container.  This is as expected.  I find your decision not to recalculate the layout of the container when the contents of the ItemsSource changes to be baffling given that you do recalculate the layout if a label changes!

To summarize.  This design is broken.  It only works if you have a preexisting set of data to populate in the listview.  Since we are talking about mobile applications I can't believe that many of them meet that criteria which in turn means that your design decisions have made the listview fatally broken for most of your clients.

Please stop waffling and implement a fix to either precalculate based on the xaml or to calculate dynamically.  The current design to precalculate based on ItemsSource is fatally flawed.
Comment 6 troywillmot 2014-12-03 19:24:17 UTC
I have spent hours trying to figure out what is going on in my app, and I now believe it is this bug.

While I can understand there are performance implications when a "non-fill layout option" is used, if a fill option is specified then it should be easy to perform the calculation and do it only once (per parent size change/layout) rather than on item add/remove which is where I think the performance problems being mentioned are an issue.

Can we not get this working for 'fill' scenarios? It seems everyone is expecting the same thing, and it should be possible?

Thanks.
Comment 7 troywillmot 2014-12-03 20:32:51 UTC
I should also point out that this problem doesn't appear to occur on WP. It does on iOS, and I presume Android, but WP works fine.

XF Layouts get converted to WP's native ones and those ones do a better job?
Comment 8 Jason Smith [MSFT] 2015-02-13 15:53:05 UTC
Triggering a relayout on ItemsSource changes for ListViews would be too expensive too implement currently.

WP does it for free so it happens there, if you wish to force it on iOS/Android call ForceLayout on the parent layout.
Comment 9 troywillmot 2015-02-13 16:37:39 UTC
Why is it too expensive for XF if WP can do it automatically? Isn't this just a sign the layout engine can and should be improved perf wise? Also, given this often leads to a completely invisible list view and therefore an app that doesn't work it would seem worth finding a solution for this.
Comment 10 troywillmot 2015-02-15 15:30:17 UTC
Reading back over the earlier comments, it seems we are not even asking for a relayout to be performed - just for the layout to be performed as expected, once, when using a fill or fill and expand layout option? Given that calculation would be to fill the available area, it shouldn't even be that complicated (doesn't involve measuring items within the list etc).

I also still question why this is done natively by WP but too slow on the other platforms?
Comment 11 Wayne Maurer 2015-02-16 03:06:42 UTC
Indeed, from my point of view, there seems to be a gap of understanding between us users who are experiencing this problem, and the Xamarin team.

@Jason. We're not asking for a relayout on ItemsSource changes for ListViews. We're simply asking that the the ListView respects the LayoutOption properties. If the ListView's VerticalLayout is set to FillAndExpand, then that's what it should do. This is _nothing_to_do_ with ItemsSource changes.
Comment 12 Jason Smith [MSFT] 2015-03-11 14:45:34 UTC
The idea that the native ones do this is simply not true (heck, the number we returned before 1.3 was just whatever the native one returned). Android actually does return the info you want, it is the only platform that does, and you can make this process take minutes just by giving it a huge collection to have to measure (give it 200k items and see how long it takes to do a height measure pass as it tries to reuse a single cell 200k times at once).

iOS returns a fixed height that isn't related to the number of items in the list (especially if the list has individual heights for cells). WP just returns a massive number assuming that it will simply be expected to fill the screen.

I'm not trying to be unreasonable, I just have no earthly idea how to give you what you want, I agree the ideal situation is that the height you get back from measuring a ListView is its exact height, it just does not seem to be in the cards. If you know how to do it reliably and quickly I am all ears (and accounting for uneven rows, etc).
Comment 13 troywillmot 2015-03-11 21:39:21 UTC
"agree the ideal situation is that the height you get back from measuring a ListView is its exact height"

No, no, no, no... with all due respect that is not what we are asking for (or at least not all of us). I appreciate you're not trying to be unreasonable, neither are we :)

First of all, we're not asking for the height to be returned (though obviously it should be in some fashion). We're asking for the height to be set to something that doesn't make the list view invisible when it has items in it. This has cost me personally hours of frustration as I try to figure out why my bindings aren't working etc. only to eventually discover everything is fine and the list items are loading etc. but the list has no height so is invisible.

Secondly, what we're really asking is WHEN THE LAYOUT OPTIONS ON THE LISTVIEW ARE SET TO FILL/EXPAND THE LISTVIEW ACTUALLY FILLS/EXPANDS TO THE AVAILABLE SPACE IN THE PARENT LAYOUT and DOES *NOT* ATTEMPT TO MEASURE A HEIGHT BASED ON ITS CONTENT.

Measuring a height based on content might be fine if the layout options aren't fill/expand, but if they are then the content is irrelevant - only the available space in the parent layout matters. If you can make fill/expand work as expected then I would expect most of us to go away happy (others can chime in if I'm wrong).

Also, from my personal point of view (and I am clearly not an expert in anything, particularly your internal code);

1. If you load 200,000 items in a list/grid control you're an idiot or made a mistake. Even on a desktop PC where resources may not be a problem this isn't a useful user experience. That aside, people create crappy UX all the time...

2. Even in the 200,000 items situation the 'height' of the control should be capped to the height of the visible items (presumably vastly less than 200k given the size of most screens) or the available parent layout/screen space. After that the listview isn't really any bigger (not in terms of screen layout), it just has scroll extents within it which are bigger. I agree calculating the scroll extents would be a problem, but the actual height for layout should only matter as far as *visible* space which should be easier/quicker to work out?
Comment 14 Jason Smith [MSFT] 2015-03-12 15:08:52 UTC
Okay I misunderstood the entire point of the bug here then. Can you send me your layout where FillAndExpand is not working? I have not seen an issue where this happens.

Keep in mind the expand flag does not chain up, it will not force its parents expand flag on.
Comment 15 Wayne Maurer 2015-03-12 15:34:30 UTC
That's what I'd said in may last post ... the ListView is not respecting the LayoutOption properties.

Jason, could you look at repro I posted in my first post:
https://github.com/wmaurer/XamarinFormsListViewRepro

Specifically the Homepage:
https://github.com/wmaurer/XamarinFormsListViewRepro/blob/master/XamarinFormsListViewRepro/XamarinFormsListViewRepro/HomePage.cs

The Content of the Page is a StackLayout, layout options set to expand. The StackLayout has a number of children, one being a ListView, layout options set to expand.

The ListView should always have a height and width in this case due to its layout options, regardless of whether it has items or not.

I hope that this help pinpoint the issue, otherwise I'm sure Troy will come back with a better repro.
Comment 16 troywillmot 2015-03-12 15:56:20 UTC
Thanks Wayne, I was just struggling with when I was going to schedule in creating a repro and why your original one wasn't good enough :)

Jason - Wayne's problem sounds the same as mine except for two things;

1. My problem was on *iOS* not Android, so the problem code *may* exist in both renderers. I believe WP doesn't suffer from this.

2. In my case I had zero items in the list when it was first rendered/sized, and then added items which is why it ended up invisible and caused me confusion. In Wayne's case it sounds like he has one item and adds more. Either case is broken if it behaves as described and probably the same fix applies to both, but there is a subtle difference there in case it matters.
Comment 17 troywillmot 2015-03-12 15:57:39 UTC
Nice we are all on the same page now. Sorry if I was forceful in getting my point across, I wasn't trying to be rude, just clear.
Comment 18 Jason Smith [MSFT] 2015-03-14 19:05:26 UTC
The issue with the reproduction case here is the usage of EndAndExpand and not FillAndExpand.

EndAndExpand tells the parent layout to give the leftover space to the particular child for its layout allocation area, but then to put that child in the smallest area it fits in at the end of that layout allocation area.

FillAndExpand does what you expect.
Comment 19 troywillmot 2015-03-15 04:57:16 UTC
Thanks Jason. I believe the problem never occurred on WP for me and all my IOS build stuff is at the office. When I get a chance I'll remove my hacks from my original app and see if the problem still occurs. If it does then I'll work on a test case. Probably won't be tomorrow as I think I have an all day meeting.
Comment 20 troywillmot 2015-03-23 16:38:40 UTC
Hi All,

As best I can tell this problem no longer occurs. I have removed my hacks to force a relayout from my app where the problem originally occurred and tested it again on iOS and WP. I can't reproduce the problem anymore, and the code shouldn't have changed otherwise, so my guess is it was fixed (intentionally or unintentionally) by an update to Xamarin Forms. I am not sure what version I was using initially so I can't go back and test.

Unless someone else can reproduce it, I suggest this is closed as fixed for now.