后台下载进度在uwp c#中没有更新

本文关键字:更新 uwp 下载 后台 | 更新日期: 2023-09-27 18:02:23

我正在研究我的新应用程序,它已经完成了,但只有我有BackgroundDownloader的问题。在一个XAML中,我使用以下代码创建下载操作:它是DownloadManagerClass:

class DownloadManager
{
    public static DispatcherTimer dt;
    //Here is Download Manager functionallity
    public static async Task<IReadOnlyList<DownloadOperation>> GetActiveDownloadsAsync()
    {
        return await BackgroundDownloader.GetCurrentDownloadsAsync();
    }
    public static ToastNotification CreateFailureToast(string FileName)
    {
        string title = "Download Failed";
        string name = FileName;
        return CreateToast(title, name);
    }
    public static ToastNotification CreateSuccessToast(string FileName)
    {
        string title = "Download Completed";
        string name = FileName;
        return CreateToast(title, name);
    }
    private static ToastNotification CreateToast(string title, string name)
    {
        // Create xml template
        XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
        // Set elements
        XmlNodeList stringElements = toastXml.GetElementsByTagName("text");
        IXmlNode element0 = stringElements[0];
        element0.AppendChild(toastXml.CreateTextNode(title));
        IXmlNode element1 = stringElements[1];
        element1.AppendChild(toastXml.CreateTextNode(name));
        // Create toast
        return new ToastNotification(toastXml);
    }

    public static async Task CreateNewDownload(Uri Uri, string FileName)
    {
        var bgdl = new BackgroundDownloader();
        bgdl.SuccessToastNotification = CreateSuccessToast(FileName);
        //var res = await ConvertUriToDownloadInfo(Uri);
        StorageFile File;
        DownloadOperation dl;
        try
        {
            File = await (await KnownFolders.MusicLibrary.CreateFolderAsync("WikiSeda", CreationCollisionOption.OpenIfExists)).
                   CreateFileAsync(FileName, CreationCollisionOption.FailIfExists);
            dl = bgdl.CreateDownload(Uri, File);
            dl.StartAsync().AsTask();
            try
            {
                StatusBar.GetForCurrentView().ProgressIndicator.Text = "Downloading...";
                await StatusBar.GetForCurrentView().ProgressIndicator.ShowAsync();
                dt = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 3) };
                dt.Tick += Dt_Tick;
                dt.Start();
            }
            catch { }
        }
        catch
        {}
    }
    private static async void Dt_Tick(object sender, object e)
    {
        dt.Stop();
        dt.Interval = new TimeSpan();
        dt.Tick -= Dt_Tick;
        dt = null;
        try
        {
            await StatusBar.GetForCurrentView().ProgressIndicator.HideAsync();
        }
        catch { }
    }

    public static async Task<IReadOnlyList<StorageFile>> GetDownloadedItemsList()
    {
        try
        {
            var WikiSeda = await KnownFolders.MusicLibrary.GetFolderAsync("WikiSeda");
            return (await WikiSeda.GetFilesAsync());
        }
        catch { return null; }
    }
}

之后,如果用户去我的下载页面看到一个列表与两种类型的数据模板。下面是Xaml代码:

<Page.Resources>
    <DataTemplate x:Key="DownloadedItemTemplate">
        <Grid Padding="10,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Image Grid.Column="0" Source="{Binding Thumb}" MaxWidth="50" MaxHeight="50" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            <Grid Grid.Column="1" VerticalAlignment="Center" Padding="10,0">
                <TextBlock Text="{Binding Message}" VerticalAlignment="Center"/>
            </Grid>
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="DownloadingTemplate">
        <Grid Padding="10,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Image Grid.Column="0" Source="{Binding Thumb}" MaxWidth="50" MaxHeight="50" VerticalAlignment="Center" HorizontalAlignment="Center"/>
            <Grid Grid.Column="1">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Message}" FontSize="15" Grid.Row="0"/>
                <ProgressBar Value="{Binding Percent, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Minimum="0" Maximum="100"/>
            </Grid>
            <Grid Grid.Column="2" VerticalAlignment="Center">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Button Background="Transparent" FontFamily="Segoe MDL2 Assets" Content="" Grid.Column="0" Click="CancelDLBTN" Tag="{Binding GUID}"/>
            </Grid>
        </Grid>
    </DataTemplate>
    <local:MessageDataTemplateSelecotr x:Key="MessageDataTemplateSelecotr" 
                                   DownloadedItemTemplate="{StaticResource DownloadedItemTemplate}" 
                                   DownloadingTemplate="{StaticResource DownloadingTemplate}"/>
</Page.Resources>
<Grid Background="{ThemeResource SystemControlForegroundChromeMediumBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <ListView Grid.Row="0" ItemTemplateSelector="{StaticResource MessageDataTemplateSelecotr}" ItemsSource="{x:Bind listViewCollection}" ItemContainerStyle="{StaticResource ListViewContainerStrecher}"
             SelectionMode="None" IsItemClickEnabled="True" ItemClick="ListView_ItemClick"/>
</Grid>

,这里是c#代码:

public class MessageDataTemplateSelecotr : DataTemplateSelector
{
    public DataTemplate DownloadedItemTemplate { get; set; }
    public DataTemplate DownloadingTemplate { get; set; }
    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
    {
        var message = item as MessageModel;
        if (message.MessageType.ToString() == "Downloaded")
            return DownloadedItemTemplate;
        else
            return DownloadingTemplate;
    }
}
public class MessageModel : INotifyPropertyChanged
{
    private Enum _MessageType { get; set; }
    private BitmapImage _Thumb { get; set; }
    private bool _IsIndeterminate { get; set; }
    private Guid _GUID { get; set; }
    private double _Percent { get; set; }
    public string Message { get; set; }
    public Enum MessageType
    {
        get
        {
            return _MessageType;
        }
        set
        {
            if (value != _MessageType)
            {
                _MessageType = value;
                OnPropertyChanged("MessageType");
            }
        }
    }
    public BitmapImage Thumb
    {
        get
        {
            return _Thumb;
        }
        set
        {
            if (value != _Thumb)
            {
                _Thumb = value;
            }
        }
    }
    public bool IsIndeterminate
    {
        get
        {
            return _IsIndeterminate;
        }
        set
        {
            if (value != _IsIndeterminate)
            {
                _IsIndeterminate = value;
            }
        }
    }
    public double Percent
    {
        get
        {
            return _Percent;
        }
        set
        {
            if (value != _Percent)
            {
                _Percent = value;
                OnPropertyChanged("Percent");
            }
        }
    }
    public Guid GUID
    {
        get
        {
            return _GUID;
        }
        set
        {
            if (value != _GUID)
            {
                _GUID = value;
            }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler == null) return;
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class PageDLs : Page
{
    List<Task> tasks = new List<Task>();
    public static CancellationTokenSource cts = new CancellationTokenSource();
    ObservableCollection<MessageModel> listViewCollection = new ObservableCollection<MessageModel>();
    private enum _MessageType
    {
        Downloaded,
        Downloading
    }
    protected override async void OnNavigatedTo(NavigationEventArgs e)
    {
        var dls = await DownloadManager.GetDownloadedItemsList();
        if (dls == null || dls.Count == 0) return;
        var d1 = dls.OrderByDescending(p => p.DateCreated);
        foreach (var item in d1)
        {
            var bmp = (await item.GetScaledImageAsThumbnailAsync(ThumbnailMode.MusicView)).AsStreamForWrite().AsRandomAccessStream();
            var bmpi = new BitmapImage();
            bmpi.SetSource(bmp);
            listViewCollection.Add(new MessageModel()
            {
                Message = item.Name,
                MessageType = _MessageType.Downloaded,
                Thumb = bmpi
            });
        }
        DetectActiveDownloads();
    }
    async void DetectActiveDownloads()
    {
        var dls = await DownloadManager.GetActiveDownloadsAsync();
        if (dls.Count == 0) return;
        foreach (var dl in dls)
        {
            tasks.Add(HandleDownloadAsync(dl, false));
            double p = 0;
            if (dl.Progress.TotalBytesToReceive > 0 && dl.Progress.BytesReceived >= 0)
                p = dl.Progress.BytesReceived / dl.Progress.TotalBytesToReceive * 100;
            listViewCollection.Add(new MessageModel()
            {
                Message = dl.ResultFile.Name,
                MessageType = _MessageType.Downloading,
                GUID = dl.Guid,
                Percent = p
            });
        }
        await Task.WhenAll(tasks);
    }
    private async Task HandleDownloadAsync(DownloadOperation download, bool start)
    {
        try
        {
            Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(ProgressCallback);
            if (start)
            {
                // Start the download and attach a progress handler.
                await download.StartAsync().AsTask(cts.Token, progressCallback);
            }
            else
            {
                // The download was already running when the application started, re-attach the progress handler.
                await download.AttachAsync().AsTask(cts.Token, progressCallback);
            }
            //progressCallback.ProgressChanged += ProgressCallback_ProgressChanged;
            ResponseInformation response = download.GetResponseInformation();
            // GetResponseInformation() returns null for non-HTTP transfers (e.g., FTP).
            string statusCode = response != null ? response.StatusCode.ToString() : String.Empty;
            foreach (MessageModel item in listViewCollection)
            {
                if (item.GUID == download.Guid)
                {
                    if (download.Progress.TotalBytesToReceive > 0 && download.Progress.BytesReceived >= 0)
                        item.Percent = download.Progress.BytesReceived / download.Progress.TotalBytesToReceive * 100;
                }
            }
            //LogStatus(
            //    String.Format(
            //        CultureInfo.CurrentCulture,
            //        "Completed: {0}, Status Code: {1}",
            //        download.Guid,
            //        statusCode),
            //    NotifyType.StatusMessage);
        }
        catch (TaskCanceledException)
        {
            //LogStatus("Canceled: " + download.Guid, NotifyType.StatusMessage);
        }
        catch (Exception ex)
        {
            //if (!IsExceptionHandled("Execution error", ex, download))
            //{
            //    throw;
            //}
        }
        finally
        {
        }
    }
    private void ProgressCallback_ProgressChanged(object sender, DownloadOperation obj)
    {
        MessageModel DLItem = null;
        foreach (var item in listViewCollection)
        {
            if (((MessageModel)item).GUID == obj.Guid) DLItem = (MessageModel)item;
        }
        if (obj.Progress.TotalBytesToReceive > 0 && obj.Progress.BytesReceived >= 0)
            DLItem.Percent = obj.Progress.BytesReceived / obj.Progress.TotalBytesToReceive * 100;
        if (DLItem.Percent == 100)
        {
            DLItem.MessageType = _MessageType.Downloaded;
            listViewCollection.Remove(DLItem);
        }
        //progress = obj.Progress.BytesReceived * 100 / obj.Progress.TotalBytesToReceive;
        //if (progress > 0)
        //{
        //    //txtProgress.Text = string.Format("Downloading your file.... {0}%", progress);
        //    //pbDownloading.Value = progress; // passing progress bar value
        //}
    }
    private void ProgressCallback(DownloadOperation obj)
    {
        MessageModel DLItem = null;
        foreach (var item in listViewCollection)
        {
            if (((MessageModel)item).GUID == obj.Guid) DLItem = (MessageModel)item;
        }
        if (obj.Progress.TotalBytesToReceive > 0 && obj.Progress.BytesReceived >= 0)
            DLItem.Percent = obj.Progress.BytesReceived / obj.Progress.TotalBytesToReceive * 100;
        if (DLItem.Percent == 100)
        {
            DLItem.MessageType = _MessageType.Downloaded;
            listViewCollection.Remove(DLItem);
        }
        //progress = obj.Progress.BytesReceived * 100 / obj.Progress.TotalBytesToReceive;
        //if (progress > 0)
        //{
        //    //txtProgress.Text = string.Format("Downloading your file.... {0}%", progress);
        //    //pbDownloading.Value = progress; // passing progress bar value
        //}
    }
}

所以我不知道的是为什么我的进度条在加载下载后不工作,我用计时器试过了,它工作得很好。由于

后台下载进度在uwp c#中没有更新

找到问题了。在ProgressCallback方法中,可以这样计算Percent:

DLItem.Percent = obj.Progress.BytesReceived / obj.Progress.TotalBytesToReceive * 100;

问题是,obj.Progress.BytesReceived是在操作进行的时候实时更新的,如果我们直接用它来计算,结果一直是0,直到下载操作结束,结果是100,而你在Percent == 100的时候删除了这个项目,所以我们看不到ProgressBar的更新。因此,我们需要做一个本地复制,以便我们计算Percent,您可以像这样修改您的ProgressCallback方法:

private void ProgressCallback(DownloadOperation obj)
{
    MessageModel DLItem = listViewCollection.First(p => p.GUID == obj.Guid);
    if (obj.Progress.TotalBytesToReceive > 0)
    {
        double br = obj.Progress.BytesReceived;
        var result = br / obj.Progress.TotalBytesToReceive * 100;
        DLItem.Percent = result;
    }
    if (DLItem.Percent == 100)
    {
        DLItem.MessageType = _MessageType.Downloaded;
        listViewCollection.Remove(DLItem);
    }
}