异步在线搜索冻结WPF-UI

时间:2016-02-03 10:12:58

标签: c# wpf multithreading async-await

我很擅长使用C#进行线程化。我有一个Searchfield,它会在按下的每个Key上触发针对API的HTTP-Request。在请求之后,Searchresult显示在我的SearchTab中的ListView中。当然,这会冻结UI几毫秒,直到HTTP-Request完成。所以我试着让Request Async。

private async void textBoxSearch_KeyUp(object sender, KeyEventArgs e)
{

    SearchTab searchTab;

    Task<SearchContainer<SearchMovie>> searchTask = searchMovie(textBoxSearch.Text);

    if (searchTabExists())
    {
        searchTab = getSearchTab();
    }
    else
    {
        searchTab = new SearchTab();
        mainTabControl.Items.Insert(mainTabControl.Items.Count, searchTab);
    }
    searchTab.IsSelected = true;

    SearchContainer<SearchMovie> results = await searchTask;
    searchTab.updateSearch(results);
}

async Task<SearchContainer<SearchMovie>> searchMovie(String query)
{
    var today = await Task.FromResult<SearchContainer<SearchMovie>>(tmdbClient.SearchMovie(query, "de"));
    return today;
}

此代码使它更好一点,但它仍然冻结了UI,因为在某些时候它必须等待API调用。我希望能够不间断地平滑地输入我的搜索,如果API-Call在另一次搜索之前及时完成(KeyPressed),则显示结果。

你如何在C#中解决这样的问题?在JAVA中,我会使用AsyncWorker在搜索完成后调用Displaymethod(或者如果进行另一次搜索则取消worker),这样就不会在Main-Thread中进行搜索和显示。

C#中是否有类似的构造?如果我搜索多线程,我只能找到异步等待解决方案。或者可以按照我希望的方式使用它。

1 个答案:

答案 0 :(得分:5)

Task.FromResult根据结果创建一个已经成功的任务。在您的示例中,结果来自对tmdbClient.SearchMovie()的调用。我认为这个电话是阻止的。

此代码并非真正异步,因为您仍在等待阻塞调用。您需要tmdbClient.SearchMovie()方法的异步版本。通常,这些是显而易见的,因为它们以Async为后缀。因此,您需要一个类似tmdbClient.SearchMovieAsync()的方法。

如果客户端库没有提供此类方法,则需要将阻塞调用转换为异步调用。

这样做的一个简单但有缺陷且有问题的方法是使用Task.Run

(这是未经测试的伪代码)

Task<SearchContainer<SearchMovie>> searchMovie(String query)
{
    return Task.Run(() => tmdbClient.SearchMovie(query, "de"));
}

这里的问题是你正在使用一个线程进行网络IO调用,这是对资源的错误使用:后台线程正在等待阻塞调用的结果,并且在阻塞调用之前不能用于任何事情完成。它应该为您提供响应更快的UI,但线程资源成本与线程相同,但异步的复杂性。