列表框选择需要更新UI的耗时任务

时间:2013-10-20 13:58:58

标签: c# wpf c#-5.0

当用户选择列表框的项目时,我有一个执行耗时任务的应用程序。

当用户选择节目时,应用程序将从tvdb中检索所有节目信息并将其显示在Ui中。

当用户在节目仍在加载时快速更改选择时,会出现问题。

我想这样做,以便用户可以改变主意,然后在第一次加载时进行另一次选择,并在Ui中显示该信息。

我创建了一个简单的演示应用程序来显示问题:Demo App

这就是我试图做的事情

列表框选择事件处理程序

private  void lb1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string sid = lb1.SelectedItem.ToString();

            try
            {
                LoadSeries(Int32.Parse(sid));
            }
            catch (FormatException)
            {
                MessageBox.Show("Please enter a valid series id");
            }
        }

LoadSeries

private void LoadSeries(int _seriesId)
{

    Task<TvdbSeries> series = Task.Factory.StartNew(() =>
    {
        TvdbSeries seriesloaded = null;
        try
        {
            seriesloaded = m_tvdbHandler.GetSeries(_seriesId, TvdbLanguage.DefaultLanguage, true, true, true, true);
        }
        catch (TvdbInvalidApiKeyException ex)
        {
            MessageBox.Show(ex.Message);
        }
        catch (TvdbNotAvailableException ex)
        {
            MessageBox.Show(ex.Message);
        }

        return seriesloaded;
    }
     );

    series.ContinueWith((antecedent) =>
    {
        UpdateSeries(series.Result);
    },
        TaskScheduler.FromCurrentSynchronizationContext()
    );

}

如果用户快速更改选择 seriesloaded = m_tvdbHandler.GetSeries(_seriesId, TvdbLanguage.DefaultLanguage, true, true, true, true); 行上的应用程序错误,并在调试器中显示此消息“ WebClient不支持并发I / O操作。

我确实发现这是因为我在最后一个请求完成之前发出了一个新请求但是我无法链接m_tvdbHandler.GetSeries中的代码,因为它的功能来自我正在使用的库和其他一些人写的

这是库tvdblib,我确定问题在于我是如何做事而不是图书馆。

2 个答案:

答案 0 :(得分:1)

当用户进行选择时,您可以禁用UI,直到信息完全加载并在底部显示消息,请等待。加载完所有内容后,启用Ui并隐藏消息。

答案 1 :(得分:0)

您将此问题发布为 C#5.0 问题,因此您应该尽可能多地使用async / await

private Task<TvdbSeries> LoadSeriesAsync(int _seriesId)
{

    return Task.Run(() =>
    {
        TvdbSeries seriesloaded = null;
        try
        {
            seriesloaded = m_tvdbHandler.GetSeries(_seriesId, TvdbLanguage.DefaultLanguage, true, true, true, true);
        }
        catch (TvdbInvalidApiKeyException ex)
        {
            MessageBox.Show(ex.Message);
        }
        catch (TvdbNotAvailableException ex)
        {
            MessageBox.Show(ex.Message);
        }

        return seriesloaded;
    }
     );
}

如果有LoadSeriesAsync,那会好得多。

一种方法是在检索系列时禁用 lb1

private async void lb1_SelectionChanged(object sender,SelectionChangedEventArgs e) {     string sid = lb1.SelectedItem.ToString();

try
{
    lb1.IsEnabled = false;
    var series = await LoadSeriesAsync(Int32.Parse(sid));

    UpdateSeries(series);
}
catch (FormatException)
{
    MessageBox.Show("Please enter a valid series id");
    lb1.IsEnabled = true;
}

}