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--
The view-model
The rest
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;
}
}