ComboBox not loading items using VirtualQueryableCollectionView

4 posts, 0 answers
  1. barak
    barak avatar
    3 posts
    Member since:
    May 2011

    Posted 21 Nov 2011 Link to this post

    We have an issue in which a RadComboBox configured with VirtualizingStackPanel
    and using an ItemsSource of VirtualQueryableCollectionView, sometimes doesn't load items, especially when scrolling to the end of it.

    For example, when the combo-box drop-down is opened and initial items are loaded,
    If you scroll straight to the end of the combo-box using the vertical scroll-bar,
    the ItemLoading event won't be triggered in the VirtualQueryableCollectionView that uses as the ItemsSource.
    The scenario is when loading items async (without RIA).


    Telerik documentation declare the RadComboBox suppose to work with VirtualQueryableCollectionView
    http://www.telerik.com/help/silverlight/using-data-virtualization.html

    So my question is, is it RadComboBox / VirtualQueryableCollectionView issue or
    is it incorrectly practicing the data virtualization (as shown in the attached sample)?

    Thanks

    -Attached is a sample that demonstrate the problem-

    --The View--
    <UserControl>
    x:Class="Telerik.Windows.Examples.ComboBox.DataVirtualization.Example"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" xmlns:local="clr-namespace:Telerik.Windows.Examples.ComboBox.DataVirtualization" mc:Ignorable="d"

    d:DesignHeight="800" d:DesignWidth="600"
    >
    <
    UserControl.Resources>
            <
    local:BindingFallbackHelperConverter x:Key="BindingFallbackHelperConverter" Value="Visible" />

            <DataTemplate x:Key="DataItemTemplate" >
                <
    Grid>
                    <
    Grid.ColumnDefinitions>
                        <
    ColumnDefinition Width="100" />
                        <
    ColumnDefinition Width="100" />
                    </
    Grid.ColumnDefinitions>
                    <
    TextBlock Text="{Binding Text}" Margin="0,0,10,0" />
                    <
    ProgressBar Grid.Column="1" Minimum="0" Maximum="100" Value="{Binding Score}"
                                 Visibility="{Binding Score, Converter={StaticResource BindingFallbackHelperConverter}, FallbackValue=Collapsed}"/>

                </
    Grid>
            </
    DataTemplate>
        </
    UserControl.Resources>
        <
    Grid>
            <
    telerik:RadComboBox Grid.Row="1" Width="250" VerticalAlignment="Top" x:Name="RadComboBox"
                    ClearSelectionButtonVisibility="Visible" ClearSelectionButtonContent="Clear selection!"

                    ItemsSource="{Binding Items}"  SelectedValuePath="Id" IsEditable="False" IsFilteringEnabled="False"

                    IsTextSearchEnabled="False" ItemTemplate="{StaticResource DataItemTemplate}">

                <
    telerik:RadComboBox.ItemsPanel>
                    <
    ItemsPanelTemplate>
                        <
    VirtualizingStackPanel />
                    </
    ItemsPanelTemplate>
                </
    telerik:RadComboBox.ItemsPanel>
            </
    telerik:RadComboBox>
        </
    Grid>
    </
    UserControl>


    public partial class Example : UserControl
    {
        public Example()
        {
            InitializeComponent();
            DataContext = new ExampleViewModel();
        }
    }



    public class BindingFallbackHelperConverter: IValueConverter
    {
        public object Value { get; set; }
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Value;
        }
         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    The view-model
    public class ExampleViewModel : ViewModelBase
    {
        private VirtualQueryableCollectionView _Items;
        private ItemsDataLoader _ItemsDataloader;
     
        public ExampleViewModel()
        {
            _Items = new VirtualQueryableCollectionView()
            {
                LoadSize = 20,
                VirtualItemCount = 1000
            };
            _Items.ItemsLoading += OnItemsLoading;
     
            _ItemsDataloader = new ItemsDataLoader();
        }
     
        void OnItemsLoading(object sender, VirtualQueryableCollectionViewItemsLoadingEventArgs e)
        {
            if(DesignerProperties.IsInDesignTool) return;
            _ItemsDataloader.GetItemsAsync(e.StartIndex, e.ItemCount, OnGetItemsCompleted, e);
        }
     
        private void OnGetItemsCompleted(ItemsAsyncCallResult asyncCallResult)
        {
            var e = (VirtualQueryableCollectionViewItemsLoadingEventArgs) asyncCallResult.UserState;
            _Items.Load(e.StartIndex, asyncCallResult.Items);
        }
     
        public ICollectionView Items
        {
            get { return _Items; }
        }
    }

    The rest
    public class DataItem: ViewModelBase
    {
        private int _Id;
        private string _Text;
        private int _Score;
     
        public int Id
        {
            get { return _Id; }
            set
            {
                _Id = value;
                OnPropertyChanged(() => Id);
            }
        }
     
        public string Text
        {
            get { return _Text; }
            set
            {
                _Text = value;
                OnPropertyChanged(() => Text);
            }
        }
     
        public int Score
        {
            get { return _Score; }
            set
            {
                _Score = value;
                OnPropertyChanged(() => Score);
            }
        }
     
        public bool Equals(DataItem other)
        {
            if(ReferenceEquals(null, other)) return false;
            if(ReferenceEquals(this, other)) return true;
            return other._Id == _Id;
        }
     
        public override bool Equals(object obj)
        {
            if(ReferenceEquals(null, obj)) return false;
            if(ReferenceEquals(this, obj)) return true;
            if(obj.GetType() != typeof(DataItem)) return false;
            return Equals((DataItem) obj);
        }
     
        public override int GetHashCode()
        {
            return _Id;
        }
     
        public override string ToString()
        {
            return Text + " (" + Score + ")";
        }
    }

    internal class ItemsAsyncCallResult
    {
        public ItemsAsyncCallResult(IEnumerable<DataItem> items, object userState)
        {
            Items = items;
            UserState = userState;
        }
     
        public IEnumerable<DataItem> Items { get; private set; }
        public object UserState { get; set; }
    }

    internal class ItemsDataLoader
    {
        public void GetItemsAsync(int startIndex, int itemCount, Action<ItemsAsyncCallResult> completionCallback, object userState)
        {
            var random = new Random();
            int delayMilliseconds = random.Next(10, 1000);
            AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(null); //remember the calling thread
            Timer timer = null;
            TimerCallback callback = delegate
            {
                OnTimerTriggered(timer, asyncOp, startIndex, itemCount, completionCallback, userState);
            };
            timer = new Timer(callback, null, delayMilliseconds, Timeout.Infinite);
        }
     
        private void OnTimerTriggered(Timer timer, AsyncOperation asyncOp, int startIndex, int itemCount, Action<ItemsAsyncCallResult> completionCallback, object userState)
        {
            timer.Dispose();
            IEnumerable<DataItem> items = LoadItems(startIndex, itemCount);
            var result = new ItemsAsyncCallResult(items, userState);
     
            SendOrPostCallback callbackOnOriginalThread = arg => completionCallback(result);
            asyncOp.PostOperationCompleted(callbackOnOriginalThread, null);
        }
     
        private IEnumerable<DataItem> LoadItems(int startIndex, int itemCount)
        {
            var items = new List<DataItem>();
            for(int index = startIndex; index < startIndex + itemCount; index++)
            {
                var item = new DataItem
                {
                    Id = index + 1001,
                    Score = (index % 101),
                    Text = "Item No " + (index + 1)
                };
                items.Add(item);
            }
            return items;
        }
    }


  2. Yordanka
    Admin
    Yordanka avatar
    634 posts

    Posted 22 Nov 2011 Link to this post

    Hi Barak,

    I have tried to reproduce the problem you report but to no avail. Here is the result of my tests. Am I doing something wrong or missing something specific that may cause the problem?
    I am attaching the test solution based on the provided code.

    Kind regards,
    Yordanka
    the Telerik team

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

  3. DevCraft banner
  4. barak
    barak avatar
    3 posts
    Member since:
    May 2011

    Posted 24 Nov 2011 Link to this post

    After performing more tests, it seems it's happen if Silverlight 5 RC is installed
    while it works under Silverlight 4.

    Isn't it RadComboBox compatible with Silverlight 5?

    Thanks
  5. barak
    barak avatar
    3 posts
    Member since:
    May 2011

    Posted 24 Nov 2011 Link to this post

    After performing more tests, it seems it's happen if Silverlight 5 RC is installed
    while it works under Silverlight 4.

    Isn't it RadComboBox compatible with Silverlight 5?

    Thanks
Back to Top