0

I am using following code to load contacts using ContactStore. My requirement is to search contacts in ContactStore when key is pressed in a textbox. Below is the code in my View Model.

   private async void LoadAllContacts(string searchQuery)
    {
        ContactStore contactStore = await ContactManager.RequestStoreAsync();

        IReadOnlyList<Contact> contacts = null;
        // Find all contacts
        contacts = await contactStore.FindContactsAsync(searchQuery);

        foreach (var item in contacts)
        {
            if (!string.IsNullOrEmpty(item.FirstName) && !string.IsNullOrEmpty(item.LastName))
            {
                var contact = new Member
                {
                    FirstName = item.FirstName,
                    LastName = item.LastName,
                    FullName = item.DisplayName, //item.HonorificNamePrefix ?? "" + item.FirstName + item.MiddleName ?? "" + item.LastName,
                    Bio = item.Notes
                };
                if (item.DataSuppliers != null)
                {
                    foreach (var dataSupplier in item.DataSuppliers)
                    {
                        switch (dataSupplier.ToLower())
                        {
                            case "facebook":
                                break;
                            case "hotmail2":
                            case "hotmail":
                                break;
                        }
                    }
                }
                if (item.Thumbnail != null)
                {
                    var thumnailStream = await item.Thumbnail.OpenReadAsync();
                    BitmapImage thumbImage = new BitmapImage();
                    thumbImage.SetSource(thumnailStream);
                    contact.ImageSource = thumbImage;
                }
                this.Insert(0, contact);
            }
        }
    }

The contacts are loading perfectly in my listview but the problem is that loading contacts from contact store is an extensive task and when user I press text in the textbox quickly then application throws exception.

My question is how can I load contacts efficiently? Means if User pressed 'a' and I call this method and quickly user pressed 'c' so if the results are loaded for 'a' then application should cancel continuing with previous operation and load 'ac' related contacts.

Thanks.

Muhammad Saifullah
  • 4,292
  • 1
  • 29
  • 59

1 Answers1

2

You should read up on the concept of CancellationTokens. That's the idea you're looking for. Lots of examples online.

CancellationToken/CancellationTokenSource is C#'s way of managing and cancelling Tasks.

In your case, you would create a CancellationTokenSource, and pass its Token object in your ContactManager.RequestStoreAsync(CancellationToken token) and contactStore.FindContactsAsync(CancellationToken token) methods (any async methods where you're awaiting).

Those two methods should accept a CancellationToken, and sporadically do a token.ThrowIfCancellationRequested().

If at some point you find that you want to stop the current Task and start a new one (for your case, when the user types something new), call CancellationTokenSource.Cancel(), which will kill the running Task thread because of the ThrowIfCancellationRequested().


One thing I want to point out though, is that your code can be optimized even further before going through CancellationTokens. You call ContactStore contactStore = await ContactManager.RequestStoreAsync(); every time. Could you not store that as a member variable?

You can also do tricks such as not running your load contacts method unless the user has stopped typing for 1 second, and I would suggest that you force concurrent Task execution in this case by using a ConcurrentExclusiveSchedular.

Community
  • 1
  • 1
dBlisse
  • 801
  • 5
  • 13