xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.63k stars 1.88k forks source link

[Bug] CarouselView CurrentItem is null on first load #9699

Closed nate123456 closed 4 years ago

nate123456 commented 4 years ago

Description

On iOS, when a CarouselView first loads, it does not have its CurrentItem property set to a value despite the view showing the first item in the ItemsSource collection. As such, I cannot use that property in my ViewModel. It also affects my ability to navigate via my ViewModel by setting the value of the Position property of the CarouselView. It seems that the null value causes some issue with the Position changed handler that doesn't occur when the CurrentItem isn't null. See the workaround section for more details that issue.

Steps to Reproduce

  1. Create a CarouselView that is bound to some collection, then bind the CurrentItem property to a property in the ViewModel (so you can track the value). Optionally bind to that property in the view or bind another view element directly to the CarouselView.
  2. Run the iOS app. Notice that the view elements that bind to the CurrentItem property have no value indicating that the property is null. Optionally watch the property in the ViewModel and notice that it does not get set to the actual currently displayed item.

Expected Behavior

The CurrentItem property is set the to the first item in the collection when the CarouselView is initialized.

Actual Behavior

The CurrentItem property is null when the CarouselView is initialized.

Basic Information

Screenshots

The image below shows my demo app displaying nothing for a Label that has its text value bound to a property of the CurrentItem Model.

Null View Element

Reproduction Link

Here is a repo I made that can demonstrate the issue. Checkout the CurrentItemNullOnFirstLoad branch and run the app on iOS.

Workaround

I can workaround the issue and use the CurrentItem property in my ViewModel if I set the property myself in the constructor or when the view appears, i.e. with OnAppearing or via a 3rd party library like Prism. Setting this not only allows me to operate on the property in my ViewModel knowing that it's correct and never has an invalid value, but it also actually affects the CarouselView and allows me to properly navigate around with a button that sets the Position property. If you wish to see the behavior of changing the position from the ViewModel when the CurrentItem is null, the demo I created above can demonstrate the issue- hit the Next button and see how it behaves.

Notes

If you're wondering why I'm not just setting the value of the CurrentItem property in my ViewModel rather than using the Position, there is a separate bug that occurs where setting the value of CurrentItem to something else in the ViewModel causes the CarouselView to set the CurrentItem back to what it was before. You can experience this by checking out the Master branch of my repo above, running the code, then attempting to navigate with the next button. More details here.

As a reference for anyone else who is trying to control their CarouselView via buttons on the view, try the following things to work around the issue:

  1. In your constructor for your ViewModel or whenever you set your ItemsSource collection, set the CurrentItem property to the first item in the collection.
  2. When attempting to navigate, use the Position property.
  3. Do not set the CurrentItem property.

I hope this helps!

jsuarezruiz commented 4 years ago

I have tested the repro sample on iOS (iOS 12 and 13) and Android. In Android it works, in iOS is where we have the issue (tested in Xamarin.Forms 4.4, 4.5 and 4.6).

Captura de pantalla 2020-02-25 a las 8 27 55

The difference between Android and iOS is the following:

cc @rmarinho

rmarinho commented 4 years ago

this should be fixed on 4.5.0.439 latest version

alexpdaniel commented 4 years ago

I am experiencing this issue with XF 4.5.0.530 on Android.

Currently getting around it using a null check.

` Article article = (Article)_carouselViewControl.CurrentItem; if (article == null) { article = ArticlesTopList.First(); }

`

If I don't scroll through the carousel, then currentitem is null.

If I scroll it forward, then back to the original, it's fine. As long as I move it, it's fine.

So I'm checking if currentitem is null, and if so, assume it is on the first item.

rmarinho commented 4 years ago

Hi @alexpdaniel can you upload a short repo ? Thanks