Hi Team,
In the current RadListView implementation, the RadListView will start with all the groups expanded. The only way to have any form of preference is to programmatically interact with the Dataview after-the-fact https://docs.telerik.com/devtools/maui/controls/listview/grouping/expand-collapse
This is problematic because I need to take a wild guess as to how long it takes for the data to load in the RadListView.Loaded event and then manually collapse them.
Even if I time this perfectly... this results in visual flash for the user because the ListView starts expanded and immediately collapses.
A better approach that I am requesting a feature for is to have a property available for the RadListView that sets this value ahead of time.
For example, you could add it as a BindableProperty on the GroupDescriptorBase class.
// THE OFFICIAL BASE CLASS
public abstract class GroupDescriptorBase : OrderedDescriptorBase, IKeyLookup
{
public object GetKey(object item) => this.GetKeyCore(item);
protected abstract object GetKeyCore(object item);
protected virtual object GetDefaultKey(object item) => item;
// SUGGESTED IMPROVEMENT
public bool IsExpanded
{
get => (bool)GetValue(IsExpandedProperty);
set => SetValue(IsExpandedProperty, value);
}
public static readonly BindableProperty IsExpandedProperty = BindableProperty.Create(
nameof(IsExpanded),
typeof(bool),
typeof(GroupDescriptorBase),
true, // the default right now is true... do not change that because no breaking changes
propertyChanged: OnIsExpandedChanged);
static void OnIsExpandedChanged(BindableObject bindable, object oldValue, object newValue)
{
if (bindable is GroupDescriptorBase self)
{
if (!(bool)newValue)
{
// PLEASE DO NOT START WITH GROUPS EXPANDED
}
}
}
}
Or you could even put it a little lower, next to the BindableProperty SortOrder:
Thank you for your consideration,
Jian
on the GroupDefinition is to have a IsExap
Currently the LoadOnDemandCollection accepts a callback of the following format in the constructor:
public LoadOnDemandCollection(Func<CancellationToken, IEnumerable> action)
It is a very common scenario to populate the items asynchronously. In its current form the collection would require blocking the current thread to populate the results:
ItemsSource = new ListViewLoadOnDemandCollection((cancelationToken) =>
{
var result = new List<ItemsModel>();
try
{
var items = dataService.GetItemsAsync().Result;
// TODO: Handle the result.
return result;
}
catch (Exception e)
{
// TODO: Handle the exception.
return null;
}
});
This is not desired, as using Task.Result blocks the current thread and is considered an anti-pattern, in general.
A better approach would be to add a second overload of the constructor, allowing asynchronous calls:
public LoadOnDemandCollection(Func<CancellationToken, Task<IEnumerable>> action)
This way we can use async and await in the callback instead:
ItemsSource = new ListViewLoadOnDemandCollection(async (cancelationToken) =>
{
var result = new List<ItemsModel>();
try
{
var items = await dataService.GetItemsAsync();
// TODO: Handle the result.
return result;
}
catch (Exception e)
{
// TODO: Handle the exception.
return null;
}
});
According to my tests, the first blocking approach is not a problem, as the ListViewLoadOnDemandCollection starts a thread internally. That behavior is not obvious however, and using Task.Result is somewhat counterintuitive, so the second approach is much better from the user's perspective.
public class City
{
public string Name { get; set; }
public string Country { get; set; }
public Image CountryFlag { get; set; }
}