Windows存储Async BackgroundDownloader未正确更新文件下载数量的UI进度

时间:2015-11-19 13:03:13

标签: c# windows-store-apps

我有需要下载的图片列表。我正在使用BackgroundDownloader和DownloadOperation。我已放置进度条以显示下载的文件数。 UI总是比下载的文件更新1。任何人都可以指出我失踪的地方。

以下是代码:

C#

public sealed partial class MainPage : Page
{
    int count = 0;
    public StorageFile ErrorFile { get; set; }
    private List<DownloadOperation> activeDownloads = new List<DownloadOperation>();
    List<string> guid = new List<string>();
    public MainPage()
    {
        this.InitializeComponent();
    }

    protected async override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        await StartDownload();
    }

    private async Task StartDownload()
    {
        BackgroundDownloader downloader = new BackgroundDownloader();
        downloader.CostPolicy = BackgroundTransferCostPolicy.UnrestrictedOnly;
        List<Task> downloadCompletionTasks = new List<Task>();

        List<string> files = GetFiles();
        totalCount.Text = (files.Count).ToString();

        progressBar1.Maximum = (files.Count);

        foreach (string url in files)
        {
            StorageFile file = null;
            file = await ApplicationData.Current.LocalFolder.CreateFileAsync(DateTime.Now.Ticks.ToString() + ".jpg", CreationCollisionOption.ReplaceExisting);
            DownloadOperation op = downloader.CreateDownload(new Uri(url), file);
            activeDownloads.Add(op);
        }

        //This forloop cannot be clubbed with above for loop because progressChanged event is accessing activeDownloads. 
        //In case of clubbing with above loop collection modified loop will be thrown.
        foreach (DownloadOperation op in activeDownloads)
        {
            Progress<DownloadOperation> progress = new Progress<DownloadOperation>(progressChanged);
            CancellationTokenSource cancellationToken = new CancellationTokenSource();
            downloadCompletionTasks.Add(op.StartAsync().AsTask(cancellationToken.Token, progress));
        }

        Task status = Task.WhenAll(downloadCompletionTasks);
    }



    private async void progressChanged(DownloadOperation downloadOperation)
    {
        foreach (DownloadOperation op in activeDownloads)
        {
            if (!guid.Contains(op.Guid.ToString()))
            {
                if (op.Progress.Status == BackgroundTransferStatus.Completed)
                {
                    await UpdateUI(downloadOperation, op);
                }
                else if (op.Progress.Status == BackgroundTransferStatus.Error)
                {
                    await UpdateUI(downloadOperation, op);
                }
            }
        }
    }

    private async Task UpdateUI(DownloadOperation downloadOperation, DownloadOperation op)
    {
        guid.Add(op.Guid.ToString());
        await this.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
        {
            count = count + 1; //guid count can be used as well
            progressBar1.Value = count;
            progressCount.Text = count.ToString();
        });

    }

    private List<String> GetFiles()
    {
        List<string> imgurl = new List<string>();
        imgurl.Add("http://images5.fanpop.com/image/photos/26700000/Snoopy-peanuts-26798453-1024-768.jpg");
        imgurl.Add("http://images.fanpop.com/images/image_uploads/Peanut-Wallpapers-peanuts-99522_1024_768.jpg");
        imgurl.Add("http://images5.fanpop.com/image/photos/25300000/peanuts-peanuts-25369428-800-600.jpg");
        imgurl.Add("http://images6.fanpop.com/image/photos/37200000/Peanuts-Movie-Wallpaper-peanuts-37225534-3996-2160.jpg");
        imgurl.Add("http://images.fanpop.com/images/image_uploads/Peanut-Wallpapers-peanuts-99520_1024_768.jpg");
        imgurl.Add("http://4.bp.blogspot.com/-wU0ljNbhyUc/TYo-LLNzqiI/AAAAAAAACQU/YxAHEOAFfCk/s1600/snoopy+peanuts+desktop+wallpaper.jpg");
        imgurl.Add("http://images5.fanpop.com/image/photos/26700000/Peanuts-peanuts-26798652-1024-768.jpg");
        imgurl.Add("http://brandthunder.com/wp/wp-content/uploads/2014/07/Peanuts-Wallpaper.jpg");
        imgurl.Add("http://3.bp.blogspot.com/-OT_HLjvXiSM/UXbByYXDU3I/AAAAAAAAAdo/6kQv7OO0v4I/s1600/snoopy-woodstock_00392750.jpg");
        imgurl.Add("http://images6.fanpop.com/image/photos/33100000/Snoopy-wallpaper-snoopy-33124725-1024-768.jpg");

        return imgurl;
    }
}

的Xaml

 <Grid Background="DarkBlue">
    <!--<Grid Background="Black" Opacity="0.6" Grid.Row="0"/>-->
    <Grid Grid.Row="0" VerticalAlignment="Center">
        <Grid VerticalAlignment="Center" Grid.Row="0" Margin="50" >
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="20"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <TextBlock Text="Downloading" x:Name="fileName" FontSize="20" Grid.Row="0"/>
            <ProgressBar x:Name="progressBar1"  IsIndeterminate="False" Grid.Row="1"/>
            <!--<TextBlock x:Name="percentTextBlock" Text="{Binding TotalProgressPercent}" Grid.Row="2" HorizontalAlignment="Center"/>-->

            <TextBlock FontSize="20" x:Name="progressCount" Text="0" Grid.Row="2" HorizontalAlignment="left"/>
            <TextBlock FontSize="20" x:Name="totalCount" Text="50" Grid.Row="2" HorizontalAlignment="Right"/>

        </Grid>

    </Grid>
</Grid>

1 个答案:

答案 0 :(得分:0)

这很可能是一个线程问题。将你的guid集合变成HashSet。如果事件同时被触发并且guid将被多次添加,那么检查guid是否是列表的一部分是可能的。 HashSet将阻止guid被添加两次。

您的计数变量不安全,因为同时调用该方法可能会覆盖它。您应该使用新的HashSet计数。

- 编辑 -

由于您已经有一个活动下载列表,只需删除像这样完成的那个:

private async void progressChanged(DownloadOperation downloadOperation)
{
    var status = downloadOperation.Progress.Status;

    if (status == BackgroundTransferStatus.Completed || status == BackgroundTransferStatus.Error)
    {
        await UpdateUI(downloadOperation);
    }
}

private async Task UpdateUI(DownloadOperation downloadOperation)
{
    await this.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
    {
        activeDownloads.Remove(downloadOperation);
        var activeCount = activeDownloads.Count;
        progressBar1.Value = activeCount;
        progressCount.Text = activeCount.ToString();
    });

}