- Home
- Forum
- Xamarin.Forms
- How to insert item into SfAutoComplete.DataSource without blocking UI thread?
How to insert item into SfAutoComplete.DataSource without blocking UI thread?
Hello,
In my solution I have SfListView with up to 100 SfAutoComplete, each has same ObservableCollection (about 50k items) as DataSource.
At the beginning I had some performance problem with creating this kind of list (it takes few seconds, so not acceptable for UI), but with some trick it was possible to solve it and now it works perfect and fast. First I noticed that there is very big performance cost for sfAutoComplete.DataSource = big50kObservableCollection, but it is very slow only if sfAutoCompete.IsVisible and also it needs to be invoked from the UI thread but only if "(autoComplete.IsDropDownOpen || (autoComplete.Text.Length>0 && autoComplete.IsFocused))". Anyway, to make long story short, I could find the way to populate all with data in background thread without blocking UI.
The problem is that now I need to modify big50kObservableCollection.
1. if user select any item, I want to mark it as favorite and move (remove and insert) at the beginning of the list so next time it will be suggested from the first character.
2. if user just enter text which is not in the big50kObservableCollection I want to make it favorite and insert it at the beginning of the list.
The problem is that even if all dropdowns are closed big50kObservableCollection.Remove and big50kObservableCollection.Insert needs to be invoked from the UI thread and because of something happened during SfAutoComplete.Handle_CollectionChanged it takes very long. When 4 sfAutoComplete are connected to big50kObservableCollection simple big50kObservableCollection.Insert(0, item) or big50kObservableCollection.Remove(item) takes over 2s, so completely not acceptable.
I tried to disconnect big50kObservableCollection from all sfAutoComplete, modify it, and connect again in background thread in same way as I did at the beginning, it seems to be impossible, because it is impossible to change already connected sfAutoComplete.DataSource. sfAutoComplete.DataSource=null or sfAutoComplete.DataSource=new ObservableCollection<ItemType>() seems to be ignored.
Could you advise me any good way how to change sfAutoComplete.DataSource without blocking UI for few seconds?
Best regards and thank you in advance for your help.
Radek
- All SfAutoComplete use same ObservableCollection as DataSource. It is important because of 2 reasons. First it is not good idea to initialise 100 x 50k business object. Second reason is that changes in one autocomplete source needs to be propagated to others.
- AutoComplete_SelectionChanged is moved to the MainPage, so it changes BookInfoRepository.Big50ObservableCollection
Attachment: AutoCompleteWithListView2_6296e0a8.zip
|
private async void AutoComplete_SelectionChanged(object sender, Syncfusion.SfAutoComplete.XForms.SelectionChangedEventArgs e)
{
var bc = (BookInfoRepository)BindingContext;
string item = e.Value?.ToString();
if (!string.IsNullOrEmpty(item))
{
await ChangeDataSource(bc, item);
}
}
private async Task<string> ChangeDataSource(BookInfoRepository bc, string item)
{
return await Task.Run(() =>
{
int index = bc.Big50ObservableCollection.IndexOf(item);
bc.Big50ObservableCollection.Move(index, 0);
return string.Empty;
});
} |
|
private async void AutoComplete_SelectionChanged(object sender, Syncfusion.SfAutoComplete.XForms.SelectionChangedEventArgs e)
{
if (cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
}
cancellationTokenSource = new CancellationTokenSource();
try
{
var bc = (BookInfoRepository)BindingContext;
string item = e.Value?.ToString();
if (!string.IsNullOrEmpty(item))
{
await ChangeDataSource(bc, item, cancellationTokenSource.Token);
}
}
// *** If cancellation is requested, an OperationCanceledException results.
catch (OperationCanceledException ex)
{
}
catch (Exception exc)
{
}
}
CancellationTokenSource cancellationTokenSource;
private async Task<string> ChangeDataSource(BookInfoRepository bc, string item, CancellationToken cancellationToken)
{
return await Task.Run(async() =>
{
int index = bc.Big50ObservableCollection.IndexOf(item);
await Task.Delay(5000);
bc.Big50ObservableCollection.Move(index, 0);
return string.Empty;
}, cancellationToken);
} |
- I could prepare my 50k data set in correct order and in format before, and then just send initial data to the SfAutoCompleteDataSource in correct format, so initiation could be instant.
- Add, Remove, Insert, Move operations could be much faster, directly on SfAutoCompleteDataSource, without destroying its special items order inside, and I guess it would be not necessary to perform any very time consuming operation each time ObservableCollection is changed
- Since there could be in my case only 1 SfAutoCompleteDataSource even if all time-consuming operations still would be necessary, it could be done only once, not for each involved SfAtuoComplete.
We are checking the performance calculated for 5000000 items. Since the performance issue need to be checked further. We will update the further details on or before Sept 12,2019.
Regards,
Kanimozhi G
Hello,
Thank you for your answer and time you spend analyzing the problem. Unfortunately, I can’t agree with result. I believe it was some kind of misunderstanding so please analyze this problem little more. Maybe there will be solution.
1stPlease take a note that my collection is not 5000000 (5000k), but 50000 (50k), so 100 times smaller.
2ndThe problem is about SfAutoComplete, not SfComboBox.
I agree that putting 5000k itmes into SfCombobox may be not the best design decision but putting 50k items into SfAutoComplete seems to be supported. There is even an example in Android Syncfusion Compontnts sample app, showing very nice performance for 100k items.
Also please take a note that all problems are because some time-consuming operation have to be done in the UI thread even if there is no obvious reason for that (all dropdowns are closed). To make things worse if more than one SfAutoComplete use same source, collection modification takes 2,3,4 times more than for 1 SfAutoComplete. It seems this very time-consuming operation in UI thread is repeated many times, even if it was enough to do it once and use same result for all SfAutoComplete.
I hope you can continue investigation and find better solution (both for iOS and Android). Even if there seems to be some work around in Android (in your example) it works not so stable, throw exceptions and after more repeats usually crashes app anyway.
Best regards,
Radek
Please let us know if you have any concern.
Regards,
Rabhia Beham K.
- 15 Replies
- 4 Participants
-
RK Radoslaw Kubas
- Aug 21, 2019 11:11 PM UTC
- Sep 18, 2019 01:58 PM UTC