chung
chung

Reputation: 1133

What's the proper way to set CachingStrategy to RecycleElement in Xamarin Forms?

I've been getting an error (but my code still runs with it so I've been ignoring it until now) saying that my BindableListView is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter.

I'm guessing this is the cause of another crash I'm getting: System.ObjectDisposedException: Cannot access a disposed object. Object name: 'Xamarin.Forms.Platform.Android.FormsTextView' because I've seen suggestions online saying that most of the time, this issue is related to the ListView, and that I should set the CachingStrategy to RecycleElement.

So I decided to finally take a look at the BindableListView and add in the CachingStrategy = "RecycleElement"

Now there was already some code implemented that seemed to try and add the CachingStrategy already:

BindableListView.cs:

namespace MyApp.Core.Controls
{
    [PropertyChanged.DoNotNotify]
    public class BindableListView : ListView
    {
        public static BindableProperty ItemClickedProperty = BindableProperty.Create(nameof(ItemClicked), typeof(ICommand), typeof(BindableListView));
        public static BindableProperty ItemAppearsProperty = BindableProperty.Create(nameof(ItemAppears), typeof(ICommand), typeof(BindableListView));
        public static BindableProperty AnimateScrollToSelectedItemProperty = BindableProperty.Create(nameof(AnimateScrollToSelectedItem), typeof(bool), typeof(BindableListView), true);

        /// <summary>
        /// Constructs a <see cref="BindableListView"/>
        /// </summary>
        /// <param name="cachingStrategy">Sets the caching strategy for the <see cref="ListView"/>.</param>
        /// <example><![CDATA[
        /// <controls:BindableListView>
        ///  <x:Arguments>
        ///    <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
        ///  </x:Arguments>
        /// </controls:BindableListView>
        /// ]]></example>
        public BindableListView(ListViewCachingStrategy cachingStrategy)
            : base(cachingStrategy)
        {
            ItemTapped += OnItemTapped;
            ItemAppearing += OnItemAppearing;
            ItemSelected += OnItemSelected;
    ...

Then in all the .xaml files that use this ListView:

<controls:BindableListView
      ...>
      <x:Arguments>
        <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
      </x:Arguments>

Would this be the correct way to set CachingStrategy to Recycle Element? If so then how would I go about fixing my error(s)?

Or should I remove the parameter from the constructor in BindableListView.cs to make it parameterless, and then just add the one line CachingStrategy = "RecycleElement" ? I tried this and the error went away at least.. (app won't run now though, "missing default ctor") but I don't know if it's the right thing to do. If this is what I'm supposed to do, will this fix my second error as well?

Thanks!

Upvotes: 0

Views: 2214

Answers (2)

ToolmakerSteve
ToolmakerSteve

Reputation: 21213

The part of the error message that applies to your situation is:

... does not define a public parameterless constructor ...

Change this:

public BindableListView(ListViewCachingStrategy cachingStrategy)
            : base(cachingStrategy)
{
    ItemTapped += OnItemTapped;
    ItemAppearing += OnItemAppearing;
    ItemSelected += OnItemSelected;
    ...
}

To this:

public BindableListView(ListViewCachingStrategy cachingStrategy)
        : base(cachingStrategy)
{
    Init();
}

public BindableListView()
        : base()
{
    Init();
}

private void Init()
{
    ItemTapped += OnItemTapped;
    ItemAppearing += OnItemAppearing;
    ItemSelected += OnItemSelected;
    ...
}

Note that you do want to keep your parameterized constructor (XAML needs that); so the solution is to add a second (parameterless) constructor.

Thus you will have both forms of constructor that are needed, and each of them will perform your initialization logic.

Upvotes: 1

Cherry Bu - MSFT
Cherry Bu - MSFT

Reputation: 10346

From your code, I think it is the correct way to set CachingStrategy to Recycle Element.

According to this document:

https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/performance

The solution to this issue is to specify a constructor on the subclassed ListView that accepts a ListViewCachingStrategy parameter and passes it into the base class:

public class CustomListView : ListView
{

   public CustomListView (ListViewCachingStrategy strategy) : base (strategy)
    {

    }
    ...
}

Then the ListViewCachingStrategy enumeration value can be specified from XAML by using the x:Arguments syntax

<local:CustomListView>
<x:Arguments>
    <ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>

Upvotes: 0

Related Questions