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

When using DataTemplate, If view is created outside the DataTemplate and returns the view instance, Created View is not loaded in the Datatemplate #4642

Open DeepikaBalaSubramaniyan opened 5 years ago

DeepikaBalaSubramaniyan commented 5 years ago

Description

We would like to bring to your notice a bug that we encountered recently, When using DataTemplate if CustomView is created outside and returns the customView instance inside the DataTemplate, Created views are not loaded in the DataTemplate. Follow the snaps to get the differences between View is created outside the DataTemplate and returns created View instance inside the DataTemplate, with Views are created inside the DataTemplate. We suspect issue was rendering native view object, Also we have attached the tree hierarchy which clearly explains while creating view outside the DataTemplate views are not converted as NativeView. For further clarification we have attached the Android renderer snaps.

CustomView is created outside the DataTemplate and returns only instance inside the DataTemplate, You can clearly see Label is not placed in Android.View.ViewGroup image

CustomView is created inside the DataTemplate, Here Label is placed in the Android.View.ViewGroup
image

In the above snaps difference is created view(Label) is not placed in Android.View.ViewGroup, This is our issue.

Steps to Reproduce

  1. Run the attached sample
  2. You can see the difference after View gets loaded , In RowIndex 0 and ColumnIndex 0 MyLabel view (Label View created in inside the DataTemplate) text was loaded with pink color
  3. At the RowIndex 0 and ColumnIndex 1 MyLabel1 view(Label View created outside the DataTeamplate and returns only View instance) was not loaded

or

ViewCell cell = new ViewCell();
cell.View = new Label() { Text = "test" };

cell.View.SetBinding(Label.TextProperty, ".");
ListView view = new ListView(ListViewCachingStrategy.RecycleElementAndDataTemplate)
{
    ItemsSource = new[] { 1, 2, 3 },
    ItemTemplate = new DataTemplate(() =>
    {
        return cell;
    }), 
};

return new ContentPage()
{
    Content = view
};

Expected Behavior

If in case of creating views outside the DataTemplate and returns the view instance, View should get loaded.

Actual Behavior

Views are not loaded while creating view outside the DataTemplate.

Basic Information

-- Version with issue: 2.5.1.527436

Screenshots

image

Reproduction Link

http://www.syncfusion.com/downloads/support/directtrac/general/ze/DataTemplate_SfDataGrid347140047 This issue was reproduced in our SfListView Control also in the same scenario For your reference we have attached the SfListView sample too http://www.syncfusion.com/downloads/support/directtrac/general/ze/ListViewSample776214805

Note : If Packages are nor restored properly, You can download the Syncfusion.Xaamrin.SfDataGrid , Syncfusion.Xamarin.SfListView packages directly from nuget.org

kingces95 commented 5 years ago

The reproduction failed to build for me. Please try and reduce your reproduction so that you start from a blank forms project without adding any additional references if possible. Note, we do not generally debug custom renderers but would rather add the features that prompted the custom renderers creation. In this case, please try and reproduce the issue without using SfListView to demonstrate the issue is with XF as opposed to SfListView. Also, generally, the DataTemplate should return a new view when it's invoked as opposed to re-using the same view.

DeepikaBalaSubramaniyan commented 5 years ago

Hi @kingces95

Tried to reproduce the sample by using Xamarin forms ListView, In Xamarin forms ListView, Normally we used ViewCell for placing the Views inside the DataTemplate, Due to the reason of CustomViews are placed inside the ViewCell and returns viewcell instance, actual issue of "While creating View outside of the DataTemplate and returning the view instance only inside the DataTemplate, views are not loaded" issue is not occurred. Here I would like to inform if I use Viewcell to placed the customViews inside the DataTemplate, outside created View is loaded like ListView in my control (SfDataGrid) too. But in my case with out placing views in Viewcell, when view is created outside the Datatemplate Created view is not loaded, Why this scenario is not worked out as expected ? And now attached our customControl(SfDataGrid) sample here http://www.syncfusion.com/downloads/support/directtrac/general/ze/DataTemplate2066273716 , and SfListView here http://www.syncfusion.com/downloads/support/directtrac/general/ze/SfListView-1730579371, Just open the sample and restore the packages from Nuget.org, After clean the solution and deploy it, Sample will get loaded without any issue. Provide your possible solution for view should get loaded when create the Views outside the DataTemplate also.

kingces95 commented 5 years ago

Yeah, not sure why it doesn't work when created outside of that delegate. It's weird. However, IMHO, we should never have allowed a delegate to be passed to that ctor. We should only have allowed a type to be passed. Below is how I'd suggest doing it. See how MySuperLabel is passed as a type? Would that work for you?

image

DeepikaBalaSubramaniyan commented 5 years ago

Hi @kingces95

Provided work around is fine, But still your suggested way has two restrictions, i) Since our control has many reusing views, If DataTemplate is working on different ways while creating Views inside and outside which will affect our control stability. ii) If I needs to write my codes on MVVM pattern which affects, So by using DataTemplate created views should work fine irrespective of views created inside or outside of the DataTemplate. So at Which release can we expect this bug will get fixed ?

PureWeen commented 5 years ago

I'll move this to enhancements but to be honest I don't think it'll be changed to how you are wanting it to work for some time (if at all)

The DataTemplate function is called whenever the ListView needs a new view to insert into the listview. It doesn't just make a copy of the "template"

So all you are getting for all your ListView items is the same instance of the view for each row. I agree with @kingces95 that supplying the factory one probably allowed for cases like this to sneak in.

Why is it important to reuse the views? The Retain Caching Strategy should just do that itself and if you just create a new view inside the Function or use the TYPE constructor instead that should be fine and you shouldn't have performance problems