我使用以下代码使用ContactStore加载联系人。我的要求是在文本框中按下键时搜索ContactStore中的联系人。以下是我的View模型中的代码。
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);
}
}
}
联系人在我的列表视图中完美加载,但问题是从联系人存储区加载联系人是一项繁重的任务,当用户我快速按下文本框中的文本时,应用程序会抛出异常。
我的问题是如何有效地加载联系人?意味着如果用户按下“a”并且我调用此方法并且快速用户按下“c”,那么如果结果加载为“a”,则应用程序应取消继续之前的操作并加载“ac”相关联系人。
感谢。
答案 0 :(得分:2)
您应该阅读CancellationTokens的概念。这就是你正在寻找的想法。网上有很多例子。
CancellationToken / CancellationTokenSource是C#管理和取消任务的方式。
在您的情况下,您将创建一个CancellationTokenSource,并在您的ContactManager.RequestStoreAsync(CancellationToken token)
和contactStore.FindContactsAsync(CancellationToken token)
方法(您正在等待的任何异步方法)中传递其Token对象。
这两种方法应该接受CancellationToken,偶尔会做token.ThrowIfCancellationRequested()
。
如果在某些时候您发现要停止当前任务并启动一个新任务(对于您的情况,当用户键入新内容时),请调用CancellationTokenSource.Cancel()
,这将终止正在运行的任务线程,因为ThrowIfCancellationRequested()
。
我想指出的一件事是,在通过CancellationTokens之前,您的代码可以进一步优化。您每次都致电ContactStore contactStore = await ContactManager.RequestStoreAsync();
。你能否将它存储为成员变量?
你也可以做一些技巧,比如没有运行你的加载联系人方法,除非用户已经停止输入1秒钟,我建议你在这种情况下使用ConcurrentExclusiveSchedular强制执行并发任务。