Filtering RadLoopingList with ObservableCollection

9 posts, 1 answers
  1. Pol
    Pol avatar
    3 posts
    Member since:
    Mar 2011

    Posted 31 Mar 2011 Link to this post

    Hello
    Is it possible to bind RadLoopingList to ObservableCollection? I want to provide filtering with ICollectionView.Filter.
    If not, what is preffered method to provide filtering for RadLoopingList?

    Best regards
    Pol
  2. Answer
    Georgi
    Admin
    Georgi avatar
    296 posts

    Posted 04 Apr 2011 Link to this post

    Hello Pol,

    Thank you for your question.

    RadLoopingList does not behave like a standard ListBox. It uses completely different approach for visualizing its items and does not rely on pre-created data items.

    Generally you will need to follow these steps in order to properly setup the control:

    - Handle the ItemNeeded event of LoopingListDataSource and provide an instance of your business object.
    - Handle the ItemUpdated event of LoopingListDataSource and set the desired properties of the associated business object, depending on the provided logical index. Note that your business object should raise the LoopingListDataItem.OnPropertyChanged with the correct property name so that the item is visually updated.
    - And of course you will need the appropriate DataTemplate applied to the RadLoopingList.ItemTemplate property.

    More information about the control may be found in our documentation and in our demo application (part of the installation package) - there are two examples that showcase control's usage.

    So, the filtering should happen when preparing the item to be visualized - either in the ItemNeeded or in the ItemUpdated event.

    I hope this helps. Let me know if you have other questions.

    All the best,
    Georgi
    the Telerik team
    Let us know about your Windows Phone 7 application built with RadControls and we will help you promote it. Learn more>>
  3. DevCraft banner
  4. Kate
    Kate avatar
    5 posts
    Member since:
    Apr 2012

    Posted 18 May 2012 Link to this post

    Can you explain more about raising the LoopingListDataItem.OnPropertyChanged event?  I can't find a good, simple example anywhere of how to update the control properly.  When I have more items in my list than can be displayed at a time on the page and scroll to see the bottom items, instead of showing the updated contents I see repeats of the initial items.

    i.e. in a list of 0 - 10 items, the 9th and 10th items will instead show the 0th and 1st items.
  5. Deyan
    Admin
    Deyan avatar
    2041 posts

    Posted 19 May 2012 Link to this post

    Hi Kate,

    Thanks for writing and for your question.

    You can read more about the INotifyPropertyChanged interface here:

    http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

    In a nutshell, this interface allows you to raise an event when a property on your business object changes thus informing the subscribers that they should refresh their state. This is a well know .NET interface that many native components use to receive notifications of updates that happen on objects created by you as a developer.

    Please let me know if you need further assistance here.

    All the best,
    Deyan
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  6. Kate
    Kate avatar
    5 posts
    Member since:
    Apr 2012

    Posted 21 May 2012 Link to this post

    Thanks Deyan,

    How does that work with the item_updated and item_needed model described in the tool section for radloopinglist here?

    For example, I am populating the radloopinglist with directions data (ItineraryData) as follows:

    public class ItineraryData : ObservableCollection<string>
    {       
        private static LoopingListDataSource src;
        private IEnumerator<BingRouteService.ItineraryItem> itineraryListEnumerator;
     
        public ItineraryData(ObservableCollection<BingRouteService.ItineraryItem> itineraryList)
        {
            src = new LoopingListDataSource(itineraryList.Count);
            itineraryListEnumerator = itineraryList.GetEnumerator();
     
            src.ItemNeeded += (sender, args) =>
            {
                if (itineraryListEnumerator.MoveNext())
                {
                    DirectionsPanel dp = new DirectionsPanel();
                    dp.distanceInfo = itineraryListEnumerator.Current.Summary.Distance.ToString() + " mi";
                    dp.directionsText = parseXML(itineraryListEnumerator.Current.Text);
                    dp.itemNumber = args.Index.ToString();
                    args.Item = new DirectionsPanel() { distanceInfo = dp.distanceInfo };
                    args.Item = new DirectionsPanel() { directionsText = dp.directionsText };
                    args.Item = new DirectionsPanel() { itemNumber = dp.itemNumber };
                }
            };
     
            src.ItemUpdated += (sender, args) =>
            {
                DirectionsPanel dp = new DirectionsPanel();
                dp.distanceInfo = itineraryListEnumerator.Current.Summary.Distance.ToString() + " mi";
                dp.directionsText = parseXML(itineraryListEnumerator.Current.Text);
                dp.itemNumber = args.Index.ToString();
                (args.Item as DirectionsPanel).distanceInfo = dp.distanceInfo;
                (args.Item as DirectionsPanel).directionsText = dp.directionsText;
                (args.Item as DirectionsPanel).itemNumber = dp.itemNumber;
            };
        }
     
        public LoopingListDataSource ItineraryDataSource
        {
            get
            {
                return src;
            }
        }

    I tried calling "Changed()" from the get on ItineraryDataSource but I ended up with an empty control when I ran it.

    Thanks for your help,
    Kate
  7. Deyan
    Admin
    Deyan avatar
    2041 posts

    Posted 22 May 2012 Link to this post

    Hi Kate,

    The ItemNeeded and ItemUpdated events are fired by the UI virtualization mechanism when new visual items are realized and bound to data items. The ItemNeeded event is fired when a visual container is created and inserted into the viewport as long as the viewport has space to accommodate visual items. The ItemUpdated event is then fired each time a new data item is about to be realized and positioned into the viewport. In this event you receive information about the needed data index and are supposed to update the visual container with the corresponding information.

    Based on the source code that you are pasting I see that you are not correctly using these events, and the ItemNeeded event in particular. Take a look at the following snippet from your code:

    args.Item = new DirectionsPanel() { distanceInfo = dp.distanceInfo };
    args.Item = new DirectionsPanel() { directionsText = dp.directionsText };
    args.Item = new DirectionsPanel() { itemNumber = dp.itemNumber };

    Here you set the same property three times with different objects. This makes no sense, as the last value that will be valid is the last DirectionsPanel instance which overrites the previous, which correspondingly overwrites the first one.

    I guess you want to make the following statement:
    args.Item = new DirectionsPanel() { distanceInfo = dp.distanceInfo, itemNumber = dp.itemNumber, directionsText = dp.directionsText  };

    Another problem that might be the reason for you not getting the desired behavior in RadLoopingList is, as already mentioned, the lack of the INotifyPropertyChanged support on your data objects. This will make it impossible for RadLoopingList to understand that you update the properties of your data items in the ItemUpdated event. You need to implement this interface and fire the PropertyChanged event when you set new values to your properties in order to get this working.

    This article on MSDN gives great hints on how to do this:

    http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

    I hope this is helpful.

    Kind regards,
    Deyan
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  8. Kate
    Kate avatar
    5 posts
    Member since:
    Apr 2012

    Posted 23 May 2012 Link to this post

    Hi Deyan,

    This was helpful and things have improved.  I am no longer getting the first several items repeated at the end of the list, rather the 9th item (because it is the first item off the page) is repeated for as many other items are not initially rendered.

    I think there is still something wrong with the way I am getting the enumerator for the list:

    src.ItemNeeded += (sender, args) =>
    {
        if (itineraryListEnumerator.MoveNext())
        {
            moved = true;
            DirectionsPanel dp = new DirectionsPanel();
            dp.distanceInfo = itineraryListEnumerator.Current.Summary.Distance.ToString() + " mi";
            dp.directionsText = parseXML(itineraryListEnumerator.Current.Text);
            dp.itemNumber = args.Index.ToString();
            args.Item = new DirectionsPanel() { distanceInfo = dp.distanceInfo, itemNumber = dp.itemNumber, directionsText = dp.directionsText };
        }
    };

    So you can see I am moving the enumerator forward when a new item is needed.  However I am not doing that if an item is updated.  I can add that logic in, but this doesn't solve the problem of when the user scrolls upward.  Do I really have to handle all this myself or is there a simpler way?

    Thanks for your help!
    Kate
  9. Kate
    Kate avatar
    5 posts
    Member since:
    Apr 2012

    Posted 23 May 2012 Link to this post

    Nevermind, I think I've got it!  I used the args.Index to figure out which item I need in the list:

                src.ItemNeeded += (sender, args) =>
                {
                    itineraryListEnumerator.Reset();
                    for (int i = 0; i <= args.Index; i++)
                    {
                        itineraryListEnumerator.MoveNext();
                        moved = true;
                    }
                    DirectionsPanel dp = new DirectionsPanel();
                    dp.distanceInfo = itineraryListEnumerator.Current.Summary.Distance.ToString() + " mi";
                    dp.directionsText = parseXML(itineraryListEnumerator.Current.Text);
                    dp.itemNumber = args.Index.ToString();
                    args.Item = new DirectionsPanel() { distanceInfo = dp.distanceInfo, itemNumber = dp.itemNumber, directionsText = dp.directionsText };
                };
     
                src.ItemUpdated += (sender, args) =>
                {
                    if (moved == false)
                    {
                        itineraryListEnumerator.Reset();
                        for (int i = 0; i <= args.Index; i++)
                        {
                            itineraryListEnumerator.MoveNext();
                            moved = true;
                        }
                    }
                    DirectionsPanel dp = new DirectionsPanel();
                    dp.distanceInfo = itineraryListEnumerator.Current.Summary.Distance.ToString() + " mi";
                    dp.directionsText = parseXML(itineraryListEnumerator.Current.Text);
                    dp.itemNumber = args.Index.ToString();
                    (args.Item as DirectionsPanel).distanceInfo = dp.distanceInfo;
                    (args.Item as DirectionsPanel).directionsText = dp.directionsText;
                    (args.Item as DirectionsPanel).itemNumber = dp.itemNumber;
                    moved = false;
                };
  10. Deyan
    Admin
    Deyan avatar
    2041 posts

    Posted 23 May 2012 Link to this post

    Hi Kate,

    Great that you've managed to handle the case.

    Let us know as soon as you have further questions or need assistance.

    Greetings,
    Deyan
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

Back to Top
DevCraft banner