RadCycleHubTile with dynamic items via Binding

14 posts, 0 answers
  1. Miguel
    Miguel avatar
    7 posts
    Member since:
    Jan 2013

    Posted 04 Apr 2013 Link to this post

    Hello Telerik support team,

    I'm trying to Data Bind a dynamic collection of Items in the RadCycleHubTile.ItemsSource property like this:

    <ListBox x:Name="SourceList"
        Margin="0,0,-12,0"
        ItemsSource="{Binding Sources}"
        SelectionChanged="SourceListSelectionChanged">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <toolkit:WrapPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <telerikPrimitives:RadCycleHubTile
                    telerikPrimitives:RadHubTileService.GroupTag="ContentsCycleTile"
                    Grid.Row="0" Grid.Column="0"
                    Width="276" Height="132"
                    Padding="12, 0, 0, 8"
                    Title="{Binding Title}"
                    FontSize="{StaticResource PhoneFontSizeMedium}"
                    Margin="12, 8, 0, 0"
                    CycleRandomly="False"
                    UpdateInterval="{Binding Path=SelectedItem, ElementName=SourceList, Converter={StaticResource TimeSpanGenerator}}"
                    ItemsSource="{Binding AllFeedItems}">
                    <telerikPrimitives:RadCycleHubTile.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="12, 6, 12, 12">
                                <TextBlock FontSize="15">
                                    On <Run Text="{Binding Date}"/>:
                                </TextBlock>
                                <Grid Margin="0, 12, 0, 0">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="50"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <Image VerticalAlignment="Top"
                                        Stretch="Uniform"
                                        Source="{Binding ImageUrl}"/>
                                    <TextBlock Text="{Binding Title}"
                                        FontSize="15"
                                        TextWrapping="Wrap"
                                        TextTrimming="WordEllipsis"
                                        Margin="12, 0, 0, 0"
                                        Grid.Column="1"
                                        VerticalAlignment="Top"
                                        HorizontalAlignment="Left"
                                        Height="70"/>
                                </Grid>
                            </StackPanel>
                        </DataTemplate>
                    </telerikPrimitives:RadCycleHubTile.ItemTemplate>
                </telerikPrimitives:RadCycleHubTile>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    Also to be noted is that this is a collection of (static) RadCycleHubTiles inside a ListBox.

    The AllFeedItems property of my ViewModel gets loaded dynamically, and more importantly asynchronously:

    private void PanoramaIntroLoaded(object sender, RoutedEventArgs e)
    {
        RadHubTileService.UnfreezeGroup("ContentsCycleTile");
        if (!App.ViewModel.PanoramaIntroVM.IsDataLoaded)
        {
            App.ViewModel.PanoramaIntroVM.Reload();
        }
    }
     
    // And then in the Reload() method:
     
    public void Reload()
    {
        foreach (MainPageVM vm in Sources)
        {
            vm.DownloadItems();
        }
        IsDataLoaded = true;
    }
     
    // And the in the DownloadItems() method:
     
    public void DownloadItems()
    {
        _WebClient = new WebClient();
        _WebClient.DownloadStringCompleted += ClientDownloadStringCompleted;
        _WebClient.DownloadStringAsync(new Uri(FeedUri));
    }
     
    // And then in the ClientDownloadStringCompleted we Clear() and then Add() items to the AllFeedItems ObservableCollection

    So the issue is that a *runtime* InvalidOperationException is thrown when this code is run, not immediately but after the AllFeedItems collection gets asynchronously modified (that is, a couple of seconds after the loaded event). This makes me think that the issue roots from the fact that the ObservableCollection is not thread safe. I have tried a couple of "ThreadSafeObservableCollection" implementations found on the web, but the same error keeps happening. This is the Exception details:

    System.InvalidOperationException was unhandled
      Message=InvalidOperationException
      StackTrace:
           at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
           at System.Collections.Generic.List`1.Enumerator.MoveNext()
           at Telerik.Windows.Controls.RadCycleHubTile.GetNextItem()
           at Telerik.Windows.Controls.RadCycleHubTile.GetItem(Boolean random)
           at Telerik.Windows.Controls.RadCycleHubTile.Update()
           at Telerik.Windows.Controls.HubTileBase.OnUpdateTimerTick(Object sender, EventArgs e)
           at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
           at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)

    Any ideas?

    Thanks!
  2. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 05 Apr 2013 Link to this post

    Hello Miguel,

    The simplest solution that I can think of is to schedule the code that modifies the collection to be executed on the UI thread with Dispatcher.BeginInvoke(). Does this work for you?

    Kind regards,
    Victor
    the Telerik team
    Have a suggestion or face a problem - you can use the Ideas & Feedback portal to submit ideas, feedback and vote for them.
  3. DevCraft banner
  4. Miguel
    Miguel avatar
    7 posts
    Member since:
    Jan 2013

    Posted 05 Apr 2013 Link to this post

    Hi Victor, thanks for you help.

    I tried what you suggested, but sadly it yields the exact same results.

    private void ClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        if (e.Error != null || e.Cancelled == true || string.IsNullOrEmpty(e.Result))
        {
            // error message
        }
        else
        {
            // Oversimplified code
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                AllFeedItems.Add(new FeedItemVM { Title = "titulo" });
            });
        }
    }


    It should be noted that this suggestion *should* work, but that's usually when the Exception is an invalid cross-thread access exception, and it usually happens when calling the ObservableCollection.Add(). As you can see in the stack trace I posted my Exception comes straight from the telerik control on the Update/GetNextItem method.

    Just for kicks I changed property CycleRandomly from False to True, and I get an exception immediately now (without even having to call ObservableCollection.Add), this may have to do because in the beginning the collection is empty?

    System.ArgumentOutOfRangeException was unhandled
      Message=
    Parameter name: index
      StackTrace:
           at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
           at System.ThrowHelper.ThrowArgumentOutOfRangeException()
           at System.Collections.Generic.List`1.get_Item(Int32 index)
           at System.Collections.ObjectModel.Collection`1.System.Collections.IList.get_Item(Int32 index)
           at Telerik.Windows.Controls.EnumerableExtensions.ElementAt(IEnumerable enumerable, Int32 index)
           at Telerik.Windows.Controls.RadCycleHubTile.GetRandomItem()
           at Telerik.Windows.Controls.RadCycleHubTile.GetItem(Boolean random)
           at Telerik.Windows.Controls.RadCycleHubTile.OnFullyInitialized()
           at Telerik.Windows.Controls.HubTileBase.OnLoaded(Object sender, RoutedEventArgs e)
           at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
           at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)


  5. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 08 Apr 2013 Link to this post

    Hello Miguel,

    Thanks for writing.
    This is indeed a bug and will be fixed in the upcoming service pack next week.
    Your Telerik points have been updated.

    Regards,
    Victor
    the Telerik team
    Have a suggestion or face a problem - you can use the Ideas & Feedback portal to submit ideas, feedback and vote for them.
  6. Miguel
    Miguel avatar
    7 posts
    Member since:
    Jan 2013

    Posted 08 Apr 2013 Link to this post

    Thanks for your reply Victor, for a minute I though I was going crazy.

    Could you let me know when the fix has been issued?

    Thanks,
    -Miguel
  7. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 09 Apr 2013 Link to this post

    Hi Miguel,

    Will do.

    Regards,
    Victor
    the Telerik team
    Have a suggestion or face a problem - you can use the Ideas & Feedback portal to submit ideas, feedback and vote for them.
  8. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 11 Apr 2013 Link to this post

    Hello Miguel,

    We will upload an internal build later today that will include this bug fix as well as others.
    Write again if you need further assistance.

    Regards,
    Victor
    the Telerik team
    Have a suggestion or face a problem - you can use the Ideas & Feedback portal to submit ideas, feedback and vote for them.
  9. Miguel
    Miguel avatar
    7 posts
    Member since:
    Jan 2013

    Posted 23 Apr 2013 Link to this post

    Hello, can we confirm this bug was fixed? And if it has, can you provide the dll version?

    Thanks!
    -Miguel Juarez
  10. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 24 Apr 2013 Link to this post

    Hello Miguel,

    Yes, it is fixed. You can download the latest release from our website which is Q1 2013 Service Pack. 

    All the best,
    Victor
    the Telerik team
    Have a suggestion or face a problem - you can use the Ideas & Feedback portal to submit ideas, feedback and vote for them.
  11. Miguel
    Miguel avatar
    7 posts
    Member since:
    Jan 2013

    Posted 02 May 2013 Link to this post

    I'm sorry Victor. I still see the issue. I have created a small repro-able demo here: http://sdrv.ms/YofDDO
    Please let me know if I'm doing something wrong.

    Gracias,
    -Miguel
  12. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 02 May 2013 Link to this post

    Hi Miguel,

    Thanks for writing again. Can you please confirm that exception being thrown is still an ArgumentOutOfRangeException? If it is now an InvalidOperationException the following explanation should clear things up:

    If you need to dynamically update the images of the cycle tile you will have to reset the ItemsSource each time. The reason for this is the following:
    The type of the items source which the hub tile works with is IEnumerable. The only way to iterate over this interface is to use the foreach loop or to call GetEnumerator() and then call MoveNext() on the enumerator each time the hub tile updates. This means that the hub tile is in a permanent loop and when you try to modify the collection that you are enumerating you will get an InvalidOperationException.

    Hope this helps.

    All the best,
    Victor
    the Telerik team
    Have a suggestion or face a problem - you can use the Ideas & Feedback portal to submit ideas, feedback and vote for them.
  13. Miguel
    Miguel avatar
    7 posts
    Member since:
    Jan 2013

    Posted 02 May 2013 Link to this post

    Two things:
    1) Yes, the exception is ArgumentOutOfRangeException as you can see in my shared code (this happens when CycleRandomly="True" otherwise is InvalidOperationException).
    2) Wouldn't calling the .Clear() method of the ObservableCollection reset the ItemsSource? Or what exactly do you mean by "reset the ItemsSource each time"? How we go to do that in a DataBound scenario?

    Thanks,
    -M

  14. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 03 May 2013 Link to this post

    Hello Miguel,

    In the latest release (Q1 2013 SP1) there is a bug fix that fixes an ArgumentOutOfRangeException when the items source is empty. By resetting the items source I mean setting it to a new value. Resetting an existing collection will not work. As I mentioned, the hub tile is inside a permanent loop. Try to create an observable collection with 10 items for example. Start a foreach loop on it and try to call Clear() inside the loop, then you'll see what I mean.

    In summary, the ArgumentOutOfRangeException should be fixed. Also, cycling sequentially while also modifying the items source is not possible.

    Regards,
    Victor
    the Telerik team
    Have a suggestion or face a problem - you can use the Ideas & Feedback portal to submit ideas, feedback and vote for them.
  15. Miguel
    Miguel avatar
    7 posts
    Member since:
    Jan 2013

    Posted 15 May 2013 Link to this post

    Ok, I see what you are saying now, it's a constant cycle. I've done a workaround now. 

    Thanks for your help Victor.

    -Miguel
Back to Top
DevCraft banner