Xamarin.Forms 1.4.0 Released

2»

Posts

  • EricHamrickEricHamrick USMember ✭✭
    edited March 2015

    @MihaiCvasnievschi When adding too many things to the observable collection degraded performance because it triggered a ui update on each add so I just created a local observablecollection that the control wasn't subscribed to, filled it, and then assigned it to my view model instance.

    ver persons = new ObservableCollection<Person>();
    -- loop to add persons --
    Persons = persons;
    

    I haven't tried but you also might be able to create a custom ObservableCollection that you could delay or disable temporarily collection change events from being fired on adds.

  • MarkRadcliffeMarkRadcliffe NZMember ✭✭✭

    It is quite easy to extend ObservableCollection to only fire the collection changed event once while adding a list of items,

    Here is a class that adds AddRange and RemoveRange that will only fire once all the items are added/removed.

    public class ObservableRangeCollection<T> : ObservableCollection<T>
    {
        public void AddRange(IEnumerable<T> items)
        {
            CheckReentrancy();
    
          foreach (var item in items)
          {
              Items.Add(item);
          }
         
          OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
    
      //-------------------------------------------------------------------------------------------------------------------------------------
    
        public void RemoveRange(IEnumerable<T> items)
        {
            CheckReentrancy();
    
            foreach (var item in items.Where(Contains))
            {
                Items.Remove(item);
            }
            
            OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
    }
    
  • MihaiCvasnievschiMihaiCvasnievschi USUniversity
    edited March 2015

    @EricHamrick my observable collection is generated on a different thread from an IEnumerable - so normally the first load of the screen shouldn't take that much time.

    Yet a lot of time is lost within the list it self rendering the content.

    When I have the list bound directly to the IEnumerable things are a bit faster. I think that's because of how the ListRenderer handles the load (maybe the adapter?). Anyway, if you guys have access to Xamarin University you'll see in the Performance training that they do recommend using IEnumerable to speed up rendering times of long ListView - naturally I would have expected for the Xamarin.Forms equivalent to work like charm with the IEnumerable but its not the case.

  • EricHamrickEricHamrick USMember ✭✭

    @MihaiCvasnievschi It should take a lot of time initially if you you are filling an observable collection the control is bound to with a lot of items very quickly after the control has been fully initialized. When you set the itemssource property of control to an empty observable collection at initialization at some point it will probably subscribe to the event defined in INotifyCollectionChanged that every observable collection implements. Every time you add an item to a normal observable collection it fires off an event that the control is listening so the control can handle the update. A single update is an an expensive process and doing many updates sequentially is something that you want to keep to a minimum. It shouldn't matter on what thread you do it on. It will probably all get pushed into the ui thread at some point in the control.

    When you bind to any nonobservable collection there are no collection change events fired when you add items.

    As for the issue with the control not working with an IEnumerable at all thats an issue that is probably only addressable by the Xamarin Forms team. My suggestion and Marks code above is just a way to continue to use an observable collection without an enormous about of a events being fired and handled by the control everytime you loop over the collection and add things quickly.

  • MihaiCvasnievschiMihaiCvasnievschi USUniversity

    @EricHamrick - in my case the observable collection is not generated by "adding" items to it. Initially the ItemSource is null - the collection gets created (constructed) on a different thread from a IEnumerable (via LINQ). So normally this should not affect the performance of the initial load of the list. But, after the collection is completed by the background thread the ListView will notice that there are new a batch of new items and it's doing it best to render as many as possible - obviously with a performance cost.

    After the initial load I'm only adding an item to the list from time to time (caused by an user action) - that's why I wanted the ListView to be scrolled on top in the first place.

    Again, the problem is not after the IEnumerable or ObservableCollection list was iterated by the ListView - it is the initial load that's causing issue. (Actually now with 1.4.1 things run smoother - so I could say it used to cause issues)

  • DevologyDevology GBMember ✭✭✭

    I have what appears to be valid XAML to enable the pull-to-refresh functionality (testing on iOS)

        <ScrollView>
            <ListView 
            ItemsSource="{Binding InstagramMessages}" 
            SelectedItem="{Binding SelectedMessage}"
            RefreshCommand="{Binding RefreshCommand}"
            IsPullToRefreshEnabled="true">
    

    But the compiler seems to think otherwise, apparently 'RefreshCommand' isn't a valid property, even though Xamarin Studio auto completes it for me.

    I wondered whether the View Model command was invalid, but it appears okay to me (public ICommand and instance exists)...

    public ICommand RefreshCommand;
    ...
    
    // In constructor...
    this.RefreshCommand = new Command(LoadMessages);
    
    ...
        public async void LoadMessages() {
    ...
    }
    

    Here's the inner exception...

    Position 16:4. No Property of name RefreshCommand found (Xamarin.Forms.Xaml.XamlParseException)
    at Xamarin.Forms.Xaml.ApplyPropertiesVisitor.SetPropertyValue (System.Object xamlelement, XmlName propertyName, System.Object value, Xamarin.Forms.BindableObject rootElement, INode node, Xamarin.Forms.Xaml.HydratationContext context, IXmlLineInfo lineInfo) [0x00540] in :0
    at Xamarin.Forms.Xaml.ApplyPropertiesVisitor.Visit (Xamarin.Forms.Xaml.ValueNode node, INode parentNode) [0x0004f] in :0
    at Xamarin.Forms.Xaml.ValueNode.Accept (IXamlNodeVisitor visitor, INode parentNode) [0x00000] in :0
    at Xamarin.Forms.Xaml.ElementNode.Accept (IXamlNodeVisitor visitor, INode parentNode) [0x00030] in :0
    at Xamarin.Forms.Xaml.ElementNode.Accept (IXamlNodeVisitor visitor, INode parentNode) [0x00067] in :0
    at Xamarin.Forms.Xaml.RootNode.Accept (IXamlNodeVisitor visitor, INode parentNode) [0x00030] in :0
    at Xamarin.Forms.Xaml.XamlLoader.Load (Xamarin.Forms.BindableObject view, System.String xaml) [0x000be] in :0
    at Xamarin.Forms.Xaml.XamlLoader.Load (Xamarin.Forms.BindableObject view, System.Type callingType) [0x0002b] in :0
    at Xamarin.Forms.Xaml.Extensions.LoadFromXaml[TView] (Xamarin.Forms.Xaml.TView view, System.Type callingType) [0x00000] in :0
    at nativeapp.InstagramPage.InitializeComponent () [0x0000c] in /Users/Rob/Documents/Devology/social-scheduler/trunk/Source/nativeapp/obj/Debug/nativeapp.Views.InstagramPage.xaml.g.cs:21
    at nativeapp.InstagramPage.get_BindingContext () [0x00032] in /Users/Rob/Documents/Devology/social-scheduler/trunk/Source/nativeapp/Views/InstagramPage.xaml.cs:25
    at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&)
    at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00002] in /Users/builder/data/lanes/2966/58ba2bc3/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:644

    I am using version 5.10.3 build 26 stable.

  • DevologyDevology GBMember ✭✭✭

    But the compiler seems to think otherwise, apparently 'RefreshCommand' isn't a valid property, even though Xamarin Studio auto completes it for me.

    Okay - silly me, I didn't realise that I needed to manually update the Xamarin.Forms Nuget packages after upgrading Xamarin Studio components earlier. It now runs okay, but I don't see the pull-to-refresh functionality as expected; I'll raise this under a new forum entry.

Sign In or Register to comment.