How to refresh a ListView when the DataTemplate changes in Xamarin.Forms

I have a ListView with two DataTemplates that are used with a DataTemplateSelector. I want the user to be able to click a button and have theListView switch between the two templates. I also have it setup so the app remembers the last view. Right now if you leave the page and go back the view changes, but i'm wondering how I can have the ListView refresh and show the new template on command/click so the user doesn't have to leave the page.

Note: I have a fixed RowHeight for each template that changes when the user hits the button as well.

Answers

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    Can you post some Images about your current situation...

  • JoshuaNovak.6915JoshuaNovak.6915 USMember ✭✭

    @AlessandroCaliaro I can post images, but i'm not sure what you need them of. Do you mean code or of the list view not refreshing?

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭

    Images of your ListView.

    It seems that you are using DataTemplateSelector to switch between two ListView. So I would like to understand what are you doing (maybe it's correct...)

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @JoshuaNovak.6915

    Try to reset the ItemsSource (I do this, after the ItemsSource is filtered in my app)
    E.g.:
    listview.ItemsSource = "";
    // Change the datatemplate...;
    listview.ItemsSource = "your source";

    Hope this helps :sunglasses:

  • JoshuaNovak.6915JoshuaNovak.6915 USMember ✭✭

    @FredyWenger I tried that, but it doesn't seem to work. I'm also using Command for the button click and not the click event, so my events are in my ViewModel.

  • JohnHardmanJohnHardman GBUniversity mod
    edited August 2017

    @JoshuaNovak.6915

    From a Xamarin blog post:

    When using DataTemplateSelectors, it’s important to keep in mind the following limitations:
    
    No more than 20 templates per ListView on Android.
    The DataTemplateSelector subclass MUST return the same template for the same data if queried multiple times.
    The DataTemplateSelector must not return another DataTemplateSelector.
    The DataTemplateSelector must not return new instances of a DataTemplate on each call, instead the same instance must be returned. Failure to do so will effectively disable virtualization and lead to a memory leak.
    

    Ref. https://blog.xamarin.com/customizing-list-view-cells-xamarin-forms-datatemplateselector/

    From your original post, I believe you may be breaching:

    "The DataTemplateSelector subclass MUST return the same template for the same data if queried multiple times."

    If I have understood your original post correctly, you will probably want to switch between two ListViews rather than use a DataTemplateSelector to modify the appearance.

  • JoshuaNovak.6915JoshuaNovak.6915 USMember ✭✭

    @JohnHardman The same template is returned every time unless the user clicks the button and changes it. Then the other template is returned each time. It's just a toggle for a large view and smaller view. Nothing crazy.

  • JohnHardmanJohnHardman GBUniversity mod

    @JoshuaNovak.6915 - The "unless" is what is breaching the rule about use of DataTemplateSelector :-) If you were to replace the ListView when the button is pressed, that would not breach any requirements of the ListView.

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @JoshuaNovak.6915
    So.. I would dump the "DataTemplateSelector", implement two DataTemplates and reassign it to the ItemTemplate like described in my code above....

  • JohnHardmanJohnHardman GBUniversity mod

    That would work too :-)

  • JoshuaNovak.6915JoshuaNovak.6915 USMember ✭✭

    @FredyWenger @JohnHardman Thanks guys! I'll give that a try shortly. It's odd that DataTemplates don't work like that normally though, since that kind of seems like the whole point of using them.

  • FredyWengerFredyWenger CHInsider ✭✭✭✭✭

    @JoshuaNovak.6915
    This is (unfortunately) not the only thing in XF, that don't work as it should :wink:

  • JoshuaNovak.6915JoshuaNovak.6915 USMember ✭✭

    @FredyWenger @JohnHardman So I ended up just removing the ListView and adding a new one. Setting the ItemsSource to nothing, changing the ItemTemplate, and then setting the ItemsSource back worked, but it doesn't work with the RecycleElement caching strategy and there doesn't seem to be a way to change it without making a new ListView. And for scrolling fast on Android the RecycleElement caching makes a big difference.

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭
    Why don't use two list view and show/hide one or the other?
  • JohnHardmanJohnHardman GBUniversity mod

    Exactly. Toggle between the two ListViews. It uses up more memory, and you'd need to be careful about modifications to the collection, but the performance would be much better.

  • JoshuaNovak.6915JoshuaNovak.6915 USMember ✭✭

    @JohnHardman @AlessandroCaliaro I don't think it's a good idea to do that since the lists have the exact same data and could be potentially really long. So unless I have two lists and change the source to nothing on the hidden one maybe.

  • JohnHardmanJohnHardman GBUniversity mod

    @JoshuaNovak.6915 - If you switched the source to nothing, you'd lose the performance advantage at time of switching. Using RecycleElement you'd hopefully be ok memory-wise. If not, you could always use a WeakReference for the ListView not currently in use, so that it could be freed up if necessary, and then re-created if necessary.

  • JoshuaNovak.6915JoshuaNovak.6915 USMember ✭✭

    @JohnHardman I haven't heard of WeakReference so i'm not really sure how i'd use that. How would setting the hidden ListView's source to nothing hurt performance?

  • JohnHardmanJohnHardman GBUniversity mod

    @JoshuaNovak.6915 -

    This is what MSDN says about WeakReference<>:

    "Represents a typed weak reference, which references an object while still allowing that object to be reclaimed by garbage collection."
    

    Ref. https://msdn.microsoft.com/en-us/library/gg712738(v=vs.110).aspx

    The performance hit when pressing the Button to switch ItemsSource (as opposed to ListView), would result from the work in doing the creation and processing of the initial group of cells that have to be generated for the initial display, including doing the template selection for each of those cells. I haven't checked, but I don't think there would be an additional hit in terms of rendering the cells, as that would happen even if switching between ListViews rather than ItemsSource. I hasten to say that I haven't actually done this, so I'm open to correction :-) Best thing is to try it both ways and run through the profiler.

  • NMackayNMackay GBInsider, University mod

    @JoshuaNovak.6915

    Hiding listview cells is costly as it increases the layout calculation in the listview viewcell elements, every property you set has an additional performance hit when you override the default layout.

    The suggestions above work better.

Sign In or Register to comment.