后台下载进度在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
//}
}
}
所以我不知道的是为什么我的进度条在加载下载后不工作,我用计时器试过了,它工作得很好。由于
找到问题了。在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);
}
}