This is a migrated thread and some comments may be shown as answers.

RadCycleHubTile with dynamic items via Binding

13 Answers 101 Views
HubTile
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Miguel
Top achievements
Rank 1
Miguel asked on 04 Apr 2013, 05:33 PM
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!

13 Answers, 1 is accepted

Sort by
0
Victor
Telerik team
answered on 05 Apr 2013, 08:50 AM
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.
0
Miguel
Top achievements
Rank 1
answered on 05 Apr 2013, 04:29 PM
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)


0
Victor
Telerik team
answered on 08 Apr 2013, 12:41 PM
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.
0
Miguel
Top achievements
Rank 1
answered on 08 Apr 2013, 05:08 PM
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
0
Victor
Telerik team
answered on 09 Apr 2013, 06:36 AM
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.
0
Victor
Telerik team
answered on 11 Apr 2013, 07:24 AM
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.
0
Miguel
Top achievements
Rank 1
answered on 24 Apr 2013, 12:19 AM
Hello, can we confirm this bug was fixed? And if it has, can you provide the dll version?

Thanks!
-Miguel Juarez
0
Victor
Telerik team
answered on 24 Apr 2013, 07:21 AM
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.
0
Miguel
Top achievements
Rank 1
answered on 02 May 2013, 07:09 AM
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
0
Victor
Telerik team
answered on 02 May 2013, 08:49 AM
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.
0
Miguel
Top achievements
Rank 1
answered on 03 May 2013, 04:33 AM
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

0
Victor
Telerik team
answered on 03 May 2013, 10:44 AM
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.
0
Miguel
Top achievements
Rank 1
answered on 15 May 2013, 06:59 AM
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
Tags
HubTile
Asked by
Miguel
Top achievements
Rank 1
Answers by
Victor
Telerik team
Miguel
Top achievements
Rank 1
Share this question
or