Hi,
I'm having a hard time wrapping my head around how to handle list view group, sort and filter descriptors in an MVVM fashion.
My scenario is pretty simple: change the grouping, sorting or filtering rules of a list view by clicking a button.
Like so: Button => click => issue View Model command => affect change to the grouping, sorting, filtering rules owned by the view model that are supposedly bound to the list view
But here are some problems:
- The descriptors cannot be bound.
- The descriptors are read-only properties of type ObservableCollection, which means that they are owned by the RadListView instance. The caller cannot set an ObservableCollection owned by the view model.
So here are a couple of ideas I have been playing around with, both pretty bad:
- So one can write descriptors with bound properties to the view model (e.g. the sorting order), and force the list view to reload from the view model (by setting the ItemsSource to a new collection instance of the same items via a binding, which is ugly and causes flickering if the item count is high but couldn't find any other way).
- Or, I'll say presumably because I haven't tested that assumption, modify the descriptors' ObservableCollection on the list view (e.g. remove an alphabetical ascending sort descriptor from the collection and add a descending sort descriptor). This means having a reference to the list around when such change is needed. To avoid coupling the view and the view model, this could happen in the parent view, or page, and be isolated from the view model. Which is not great for reusing those features in different views with the same view model...
Does anyone have real life experience on that matter and could enlighten us on how to approach this?
And question for the Telerik staff: Why aren't the descriptor properties bindable and/or settable? Are they planned to be bindable and/or settable at some point?
Thanks in advance,
Jonathan
9 Answers, 1 is accepted

Some interesting findings on a ~400 items list while changing the grouping (or sorting):
- NOT changing the ItemsSource BUT changing the descriptors (clear the descriptors collection then add a new descriptor) = huge lag
- NOT changing the descriptors (using delegates to pick the right property to group or sort by) BUT changing the ItemsSource (just to trigger the descriptors to be re-evaluated, it's a new instance but the items are the same) = totally smooth
Thank you for contacting us!
Indeed, currently Listview descriptors are not bindable properties which makes them hard to be consumed directly in the viewmodel. Currently, it can be achieved by using attached behavior by passing its instance from the listview into the viewmodel.
We do have plans to make these properties bindable for easier usage from viewmodel directly. I have logged this as a public feedback item, so you can track its progress - https://feedback.telerik.com/Project/168/Feedback/Details/211065-listview-make-descriptors-collection-bindable-properties.
Regarding the performance issue reported - would it be possible to share come additional information regarding the setup as well as the platform on which you encounter this problem.
Regards,
Tsvyatko
Telerik by Progress

Hi Tsvyatko,
Thanks for opening a public feedback item!
The performance issue is most apparent on Android. I benchmarked the number of calls made to the sorting and grouping descriptors' extractor and comparer methods on Android and iPhone with the same collection containing 428 objects.
This is the result when changing the grouping descriptors; actually, an instance of the same delegate descriptor is inserted in the collection:
- iOS:
- sort comparer: 3249
- group extractor: 427
- Android (a Moto X will hang for about 10 seconds with a debug build):
- sort comparer: 12707
- group extractor: 1015
So ~4x the hit the amount of work!
Removing the grouping on the Android build reduces the hit by half.
Also, I noticed that:
- making the sort comparer only return 0 has little to no effect on the performance hit.
- clearing the descriptors' collection before adding a new one ends up in twice the amount of operations or so.
- modifying any of the descriptor collections makes all the descriptors to be re-evaluated (the old descriptor about to be removed is also evaluated)
Is there a preferred way to deal with descriptor? Is there a tutorial or an example showing best practices?
Let me know if I can help in anyway, this is really a show stopper.
Best regards,
Jonathan

Hi,
I've set up a minimal test project that can be downloaded here (for the next 15 days): https://we.tl/JcFRUfNFpF
It highlights the issues I've been describing.
Best regards,
Jonathan

Hi,
Further testing seems to indicate that the fastest way to refresh the list view (forcing it to re-evaluate the descriptors) is to assign the bound items source to a new instance, which would end up in something like this:
Items = new ObservableCollection<Item>(Items);
Using MVVM Light, I would have expected raising a property changed event to do the trick:
RaisePropertyChanged(nameof(ViewModel.Items));
The event is received when listening to changes, but the list view is not refreshed...
I've updated the previous sample project with MVVM Light and Realm (download will work for the next 15 days): https://we.tl/RQ7Mk3YWtV
Best regards,
Jonathan
Thank you for the attached project. I was able to test your project, and create my own project too, only to confirm that this scenario is suspiciously slow in Android. I do not think that the hit count itself is a problem, because using the sorting from System.Linq gives me a higher hit count. However System.Linq sorting is super fast for this, and a larger, data set, which suggests that the performance in Android can be improved. I will log this so that we can investigate in detail.
I created a feedback item which you can vote for and track its status. I have updated your Telerik points as a thank you for letting us know of this issue and helping us improve our product.
At the moment we cannot suggest a better approach. Let us know if you have other questions.
Regards,
Petar Marchev
Telerik by Progress

Hi Petar,
Thanks for creating a feedback item for the performance issue.
Back to my previous question:
[quote]Further testing seems to indicate that the fastest way to refresh the list view (forcing it to re-evaluate the descriptors) is to assign the bound items source to a new instance, which would end up in something like this:
Items = new ObservableCollection<Item>(Items);
Using MVVM Light, I would have expected raising a property changed event to do the trick:
RaisePropertyChanged(nameof(ViewModel.Items));
The event is received when listening to changes, but the list view is not refreshed...[/quote]
Best regards,
Jonathan
I don't see a problem with the scenario you propose. When invoking the PropertyChanged notification, you are essentially saying that this property changed and anybody interested in this change should update accordingly. However, in reality your property value did not change, and the framework detects this, and since there has been no change - the PropertyChanged chain is not triggered.
Consider this custom view:
public
class
CustomView : View
{
public
static
readonly
BindableProperty ItemsSourceProperty = BindableProperty.Create(
nameof(ItemsSource),
typeof
(IEnumerable),
typeof
(CustomView),
null
,
BindingMode.OneWay,
null
,
OnItemsSourcePropertyChanged);
public
IEnumerable ItemsSource
{
get
{
return
(IEnumerable)
this
.GetValue(ItemsSourceProperty);
}
set
{
this
.SetValue(ItemsSourceProperty, value);
}
}
private
static
void
OnItemsSourcePropertyChanged(BindableObject bindable,
object
oldValue,
object
newValue)
{
}
}
You can now use it the same way you are using the listview:
var customView =
new
CustomView
{
BindingContext = vm,
};
listView.SetBinding(RadListView.ItemsSourceProperty,
new
Binding(nameof(ViewModel.Source)));
customView.SetBinding(CustomView.ItemsSourceProperty,
new
Binding(nameof(ViewModel.Source)));
Place a break point in the OnItemsSourceChanged handler and see that the handler is not invoked upon raising the property changed notification.
Even if the handler was invoked, this does not guarantee an update, because often we use a specific object to handle the items, something like a CustomItemsSourceProxy. And in the previously mentioned OnItemsSourcePropertyChanged handler, the code looks like this:
private
static
void
OnItemsSourcePropertyChanged(BindableObject bindable,
object
oldValue,
object
newValue)
{
RadVisual v = (RadVisual)bindable;
v.itemsSourceProxy.ItemsSource = newValue;
}
So again here the proxy will not detect a change in its ItemsSource and no action will be triggered. I hope this explanation helps.
Regards,
Petar Marchev
Telerik by Progress

Hi Petar,
Thank you very much for the clarification.
Best regards,
Jonathan