xamarin / Xamarin.Forms

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

[Bug] NullReferenceException when returning null from DataTemplateSelector.OnSelectTemplate #15052

Open bakerhillpins opened 2 years ago

bakerhillpins commented 2 years ago

Description

Returning null from DataTemplateSelector.OnSelectTemplate(object item, BindableObject container) results in NullReferenceExceptions. The Xamarin documentation from MS isn't clear on this being valid or not, However, the WPF documentation is clear that null is a valid return value.

The Xamarin Example docs don't list a null return as a limitation either.

I've always returned null as a default case for desktop apps, and I am surprised this is throwing in Xamarin. It seems reasonable that null would be valid, since the absence of a DataTemplate definition for various ItemTemplate properties works without incident.

Steps to Reproduce

  1. Load and run the provided example
  2. Select the VerticalListDataTemplateSelector Page and receive the exception.

Expected Behavior

Returning null from DataTemplateSelector.OnSelectTemplate(object item, BindableObject container) should result in the item being displayed in the default manner, as if the ItemTemplate property wasn't set at all.

Actual Behavior

See lines 13/14 in CollectionViewDemos\Controls\MonkeyDataTemplateSelector.cs

NullReferenceExceptions from a variety of different places. This particular example throws here:

**System.NullReferenceException:** 'Object reference not set to an instance of an object.
  at Xamarin.Forms.Platform.Android.TemplatedItemViewHolder.Bind (System.Object itemBindingContext, Xamarin.Forms.ItemsView itemsView, System.Action`1[T] reportMeasure, System.Nullable`1[T] size) [0x0008d] in C:\Advanced Dev\Xamarin.Forms\Xamarin.Forms.Platform.Android\CollectionView\TemplatedItemViewHolder.cs:81 
  at Xamarin.Forms.Platform.Android.ItemsViewAdapter`2[TItemsView,TItemsViewSource].BindTemplatedItemViewHolder (Xamarin.Forms.Platform.Android.TemplatedItemViewHolder templatedItemViewHolder, System.Object context) [0x00001] in C:\Advanced Dev\Xamarin.Forms\Xamarin.Forms.Platform.Android\CollectionView\ItemsViewAdapter.cs:140 
  at Xamarin.Forms.Platform.Android.StructuredItemsViewAdapter`2[TItemsView,TItemsViewSource].BindTemplatedItemViewHolder (Xamarin.Forms.Platform.Android.TemplatedItemViewHolder templatedItemViewHolder, System.Object context) [0x00042] in C:\Advanced Dev\Xamarin.Forms\Xamarin.Forms.Platform.Android\CollectionView\StructuredItemsViewAdapter.cs:103 
  at Xamarin.Forms.Platform.Android.ItemsViewAdapter`2[TItemsView,TItemsViewSource].OnBindViewHolder (AndroidX.RecyclerView.Widget.RecyclerView+ViewHolder holder, System.Int32 position) [0x00044] in C:\Advanced Dev\Xamarin.Forms\Xamarin.Forms.Platform.Android\CollectionView\ItemsViewAdapter.cs:76 
  at Xamarin.Forms.Platform.Android.StructuredItemsViewAdapter`2[TItemsView,TItemsViewSource].OnBindViewHolder (AndroidX.RecyclerView.Widget.RecyclerView+ViewHolder holder, System.Int32 position) [0x00074] in C:\Advanced Dev\Xamarin.Forms\Xamarin.Forms.Platform.Android\CollectionView\StructuredItemsViewAdapter.cs:92 
  at Xamarin.Forms.Platform.Android.SelectableItemsViewAdapter`2[TItemsView,TItemsSource].OnBindViewHolder (AndroidX.RecyclerView.Widget.RecyclerView+ViewHolder holder, System.Int32 position) [0x00001] in C:\Advanced Dev\Xamarin.Forms\Xamarin.Forms.Platform.Android\CollectionView\SelectableItemsViewAdapter.cs:22 
  at Xamarin.Forms.Platform.Android.GroupableItemsViewAdapter`2[TItemsView,TItemsViewSource].OnBindViewHolder (AndroidX.RecyclerView.Widget.RecyclerView+ViewHolder holder, System.Int32 position) [0x00057] in C:\Advanced Dev\Xamarin.Forms\Xamarin.Forms.Platform.Android\CollectionView\GroupableItemsViewAdapter.cs:64 
  at AndroidX.RecyclerView.Widget.RecyclerView+Adapter.n_OnBindViewHolder_Landroidx_recyclerview_widget_RecyclerView_ViewHolder_I (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_holder, System.Int32 position) [0x00010] in D:\a\1\s\generated\androidx.recyclerview.recyclerview\obj\Release\monoandroid9.0\generated\src\AndroidX.RecyclerView.Widget.RecyclerView.cs:581 
  at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.65(intptr,intptr,intptr,int)

Basic Information

Reproduction Link

CollectionViewDemos.zip

Workaround

See this comment for a possible workaround.

jfversluis commented 2 years ago

Same as #15051 could you validate that this still happens in the latest stable version? Thanks!

bakerhillpins commented 2 years ago

Same as #15051 could you validate that this still happens in the latest stable version? Thanks!

Yes, it's in the latest code. Sorry for not putting that in there. I should have just updated the Forms Example code that I used to repo it but I didn't, I've been building the tip of the 5.0 branch to look at what's going on. There are several places in the code where this is going to be an issue. Lots of places that bind to DataTemplates.

bakerhillpins commented 2 years ago

@jfversluis 2 important points:

  1. I see you tagged this issue as a/ListView - The repo project uses CollectionView.
  2. After poking around a bit this appears to be a pervasive problem with code that allows binding to a DataTemplate/DataTemplateSelector.
jfversluis commented 2 years ago

Whoops sorry about that! It's coming up on the end of the day/week here, losing focus 😅

Thanks for the (quick) response! If you are actually building the source and are willing and able to maybe fix it yourself I think that could greatly increase your chances and the speed of this being resolved and included.

We're doing the best we can right now, but there is still a lot to do, so if there is anything you could offer in that regard it would be greatly appreciated.

bakerhillpins commented 2 years ago

Whoops sorry about that! It's coming up on the end of the day/week here, losing focus 😅

No worries.. I've been there myself.

If you are actually building the source and are willing and able to maybe fix it yourself I think that could greatly increase your chances and the speed of this being resolved and included.

I'm looking into that as I'd really like to see this fixed but as I mentioned this is bigger than CollectionView. Learning curve is steep too.

We're doing the best we can right now, but there is still a lot to do, so if there is anything you could offer in that regard it would be greatly appreciated.

Totally understand. I'm eager for all of this and well aware of your situation, it seems to be SOP for all of us these days.

JackDevAU commented 2 years ago

As a work around you can return

new DataTemplate(typeof(ContentView));

which seems to not render the item at all :)

bakerhillpins commented 2 years ago

@JackDevAU Yes, that avoids the exception, but as you noticed it displays nothing, and for several controls it's actually supplying the wrong type of View container. As I worked through the PR I noted that the default template is dependent upon both the control and in a few cases the platform as well.

With a little experimentation you could come up with a proper default for each circumstance, such as a Label where the Text Property is bound to the BindingContext and is wrapped in the proper View container. Which should result in presenting the type of the object assigned to the BindingContext as a string, so you'd see something.