question

UniversalCoder12-1951 avatar image
0 Votes"
UniversalCoder12-1951 asked RobCaplan edited

When importing a contact list from phone contacts to app,there is delay if the list is long-1000 contacts.Want to cut this delay by batch loading ie sending a list with first 10 contacts,render those to screen,second list with the remaining after it

private ObservableCollection<Models.InvitableContact> _contactItems;
public ObservableCollection<Models.InvitableContact> ContactItems
{
get { return _contactItems; }
set { Set(ref _contactItems, value); }
}
private Models.InvitableContact _selectedContact;
public Models.InvitableContact SelectedContact
{
get { return _selectedContact; }
set
{
if (!Set(ref _selectedContact, value)) { return; }
// OnInviteCommandInvoked();
ThreadHelper.RunOnMainUI(async () => await OnInviteCommandInvoked());
}
}
private string _searchContactName;
public string SearchContactName
{
set { Set(ref _searchContactName, value); }
get { return _searchContactName; }
}

  private bool _hasPermission = false; 
  public bool HasPermission 
  { 
      set { Set(ref _hasPermission, value); } 
      get { return _hasPermission; } 
  } 
  private bool _lackPermission = false; 
  public bool LacksPermission 
  { 
      set { Set(ref _lackPermission, value); } 
      get { return _lackPermission; } 
  } 
  public Task OnAppearingAsync() 
  { 
      return Task.Run(async () => await OnAppearing()); 
  } 
  protected async Task OnAppearing() 
  { 
      SelectedContact = null; 
      var appContacts = catalog.Contacts.Get(); 
      if (_contactsRequestCount >= 2 || HasPermission) return; 
      _contactsRequestCount++; 
      //check Contact permission status -- For Android version above 7.0 API 23  
      var hasContactsPermission = await PermissionCheck.HasContactsPermissions(App.Current.MainPage);
      if (hasContactsPermission) 
      { 
          var allContacts = await DependencyService.Get<IContactService>().GetAllContacts(); 
          HasPermission = allContacts.hasPermission; 
          LacksPermission = !allContacts.hasPermission; 
          var invitable = from inphone in allContacts.contacts.Distinct().GroupBy(m => m.Number).Where(m => m.Any()).Select(m => m.FirstOrDefault())
                           join inapp in (appContacts) on inphone.Number equals inapp.Number into grouped
                           from row in grouped.DefaultIfEmpty() 
                           where row == null 
                           orderby inphone.Name ascending 
                           select inphone; 
          // filter out contacts (empty name, etc) 
          var invitableFiltered = (from x in invitable 
                                   where x.Name != null 
                                   where x.Name != "" 
                                   select x); 
          // Don't add/check the same things 
          var invitableContacts = invitableFiltered.Where(m => !SelectableContacts.Any(n => n.Name == m.Name && n.Numbers.Any(nn => nn.Key == m.Number)));
          var contactsToCheck = invitableContacts.GroupBy(c => c.Name); 
          foreach (var ctc in contactsToCheck) 
          { 
              var numbers = new List<KeyValuePair<string, Xamarin.Contacts.PhoneType>>(); 
              foreach (var set in ctc) 
              { 
                  // TODO: - Check the numbers here? 
                  numbers.Add(new KeyValuePair<string, Xamarin.Contacts.PhoneType>(set.Number, set.PhoneType)); 
              } 
              var result = new Models.InvitableContact(ctc.Key, numbers); 
              SelectableContacts.Add(result); 
          } 
          OnSearchContactsFromList(); 
          string json; 
          var user = catalog.Accounts.Get().FirstOrDefault(); 
          int area = Convert.ToInt32(user.AreaCode); 
          string phonenumber = user.Number; 
          bool search_twice = true; // search twice if areacodes are not guaranteed to be included in the list "Contacts".


//here I want to batch load contact list say 10 contacts and rest immediately after it.

json = "{\"AreaCode\":\"" + area + "\", \"phonenumber\":\"" + phonenumber + "\", \"twice\":\"" + search_twice + "\", \"Contacts\": [" + String.Join(",", SelectableContacts.Select(r => r.AsJson())) + "]}";

          RunCheckAndUpdate(json); 
               
      } 
      else 
      { 
          HasPermission = false; 
          LacksPermission = true; 
          MessagingCenter.Send(this, Constants.MessageCenterConstants.CONTACTS_PERMISSION_DENIED, ContactsPermissionInfo);
      } 
  } 
  private void RunCheckAndUpdate(string json) 
  { 
      Task.Run(async () => await CheckAndUpdate(json)); 
  } 
         
  private async Task CheckAndUpdate(string json) 
  { 
      var user = catalog.Accounts.Get().FirstOrDefault(); 
      string apitoken = user.ApiToken; 
      try 
      { 
          string url = "https://*************/api/findallusers"; 
          HttpClient httpClient = ApiResourceExtensions.HttpClientWithAuth2(apitoken); 
          var content = new StringContent(json, Encoding.UTF8, "application/json"); 
          var result = await httpClient.PostAsync(url, content); 
          if (result.StatusCode == HttpStatusCode.OK) 
          { 
              // Handle results 
              var body = await result.Content.ReadAsStringAsync(); 
              var definition = new { 
                  Matches = Enumerable.Empty<object>().Select(o => new { Name = "", AreaCode = "", Number = "" }) 
              }; 
              var matches = Newtonsoft.Json.JsonConvert.DeserializeAnonymousType(body, definition).Matches;
              foreach (var contact in SelectableContacts) 
              { 
                  var key = contact.NameAsKey(); 
                  foreach (var match in matches) 
                  { 
                      if (match.Name == key) 
                      { 
                          contact.ExistingNumbers.Add(new KeyValuePair<string, string>(match.AreaCode, match.Number)); 
                      } 
                  } 
                  contact.CheckedExistingNumbers = true; 
              } 
              // Force Re-render 
              ThreadHelper.RunOnMainUI(() => 
              { 
                  ContactItems = new ObservableCollection<Models.InvitableContact>(); 
                  OnSearchContactsFromList(); 
              }); 
          } 
          else 
          { 
              FM.Log.Debug($"Failed to call findusers - StatusCode {result.StatusCode}"); 
          } 
      } 
      catch(Exception e) { 
          FM.Log.Debug("Failed to call findusers", e); 
      } 
  } 

dotnet-csharpdotnet-xamarindotnet-sqlite
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

KyleWang-MSFT avatar image
1 Vote"
KyleWang-MSFT answered KyleWang-MSFT commented

Hi UniversalCoder12-1951,

Welcome to our Microsoft Q&A platform!

Which control do you use to display contact information? ListView or CollectionView?

If you are using ColectionView, You can set RemainingItemsThreshold and RemainingItemsThresholdReachedCommand to load data incrementally.

For more info, you can refer to Load data incrementally.

And here is a simple demo you can refer to.
CollectionView.xaml

 <CollectionView
         VerticalScrollBarVisibility="Always"
         ItemsSource="{Binding ContactToDisplay}"
         RemainingItemsThreshold="10"
         RemainingItemsThresholdReachedCommand="{Binding LoadContactCommand}">
    
     <CollectionView.ItemTemplate>
         <DataTemplate>
             <Frame>
                 <StackLayout>
                     <Label Text="{Binding Name}"/>
                     <Label Text="{Binding Number}"/>
                     <Label Text="{Binding Location}"/>
                 </StackLayout>
             </Frame>
         </DataTemplate>
     </CollectionView.ItemTemplate>
 </CollectionView>

ContactViewModel.cs

 class ContactViewModel : BaseViewModel
 {
     public Command LoadContactCommand { get; set; }
    
     public ContactViewModel()
     {
         LoadContactCommand = new Command(LoadContact);
         InitContact();
     }
    
     int startIndex = 1;
     // add 10 contacts once
     int showOnScreenCount = 10;
    
     private void LoadContact()
     {
         // add new item to ContactToDisplay
         ContactToDisplay.AddRange(
             AllContacts.Skip(showOnScreenCount * startIndex).Take(showOnScreenCount)
         );
    
         startIndex++;
     }
    
     public List<Person> AllContacts { get; set; }
    
     ObservableRangeCollection<Person> contactToDisplay;
    
     public ObservableRangeCollection<Person> ContactToDisplay
     {
         get => contactToDisplay;
         set => SetProperty(ref contactToDisplay, value);
     }
    
     private void InitContact()
     {
         AllContacts = new List<Person>();
         for (var i = 1; i <= 1000; i++)
         {
             AllContacts.Add(new Person
             {
                 Name = "NAME" + i.ToString(),
                 Number = "NUMBER" + i.ToString(),
                 Location = "LOCATION" + i.ToString()
             }); ;
         }
    
         contactToDisplay = new ObservableRangeCollection<Person>(AllContacts.Take(showOnScreenCount).ToList());
     }
 }

Regards,
Kyle


If the response is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

anonymous userWang-MSFT Thank you so much for the reply. I am using ListView to display the contact list. Is there a similar approach for ListView or any sample code to load data incrementally without purchasing any lisensed library like ComponentOne. That would be very helpful.

0 Votes 0 ·
KyleWang-MSFT avatar image KyleWang-MSFT UniversalCoder12-1951 ·

@UniversalCoder12-1951 I am afraid there is no such built-in function for ListView. You can use CollectionView instead of ListView. It can also achieve the function of ListView.

0 Votes 0 ·