locked
Background Transfer Binding in Universal App

    Question

  • anyone knows how can i bind background transfer to GridView with TextBlock and ProgressBar in order to display and manage multiple downloads? 

    Here's my xaml code:

    <Grid Grid.Column="0" Background="Red">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.2*"/>
                    <ColumnDefinition Width="0.7*"/>
                </Grid.ColumnDefinitions>
                <StackPanel Grid.Column="0" Orientation="Vertical">
                    <TextBlock Text="URL :" Margin="10" FontSize="24"/>
                    <TextBlock Text="File Name :" Margin="10" FontSize="24"/>
    
                </StackPanel>
                <StackPanel Grid.Column="1" Orientation="Vertical">
                    <TextBox x:Name="tbx_url" Margin="10"/>
                    <TextBox x:Name="tbx_filename" Margin="10"/>
                    <Button x:Name="ButtonDownload" Content="Start Download" HorizontalAlignment="Right" VerticalAlignment="Top" Click="ButtonDownload_Click"/>
                    <Button x:Name="RefreshDownload" Content="Refresh" HorizontalAlignment="Right" VerticalAlignment="Top" Click="ButtonRefresh_Click"/>
                </StackPanel>
            </Grid>
            <Grid Grid.Column="1" Background="Gray">
                <Grid Margin="12">
                    <GridView x:Name="gv_downloads" ItemsSource="{Binding DownloadOperation}">
                        <GridView.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Vertical">
                                    <TextBlock Text="{Binding Progess.Status}" FontSize="22" Margin="2,2,2,2"/>
                                    <ProgressBar Value="{Binding Progess.BytesReceived}" Maximum="{Binding Progess.TotalBytesToReceive}" Margin="2,2,2,2"></ProgressBar>
                                    <Button Content="Cancel"/>
                                </StackPanel>
                            </DataTemplate>
                        </GridView.ItemTemplate>
                    </GridView>
                </Grid>
            </Grid>

    And here's my code behind:

    public sealed partial class MainPage : Page
        {
            DownloadOperation downloadOperation;
            CancellationTokenSource cancellationToken;
    
            BackgroundDownloader backgroundDownloader = new BackgroundDownloader();
            public MainPage()
            {
                this.InitializeComponent();
                this.Loaded += MainPage_Loaded;
            }
    
            void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                Refresh();
            }
            async void Refresh()
            {
                IReadOnlyList<DownloadOperation> downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();
                gv_downloads.ItemsSource = downloads;
                if (downloads.Count > 0)
                {
                    downloadOperation = downloads.First();
                    cancellationToken = new CancellationTokenSource();
                    Progress<DownloadOperation> progress = new Progress<DownloadOperation>(progressChanged);
                    ButtonDownload.IsEnabled = false;
                    
                    try
                    {
                        await downloadOperation.AttachAsync().AsTask(cancellationToken.Token, progress);
                    }
                    catch (TaskCanceledException)
                    {
                    downloadOperation.ResultFile.DeleteAsync();
    downloadOperation = null;
                    }
                }
            }
    
            /// <summary>
            /// Invoked when this page is about to be displayed in a Frame.
            /// </summary>
            /// <param name="e">Event data that describes how this page was reached.  The Parameter
            /// property is typically used to configure the page.</param>
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
            }
    
            private void ButtonDownload_Click(object sender, RoutedEventArgs e)
            {
                StartDownload(tbx_url.Text.Trim(), tbx_filename.Text.Trim());
            }
    
            private async void StartDownload(string url, string FileName)
            {
                FolderPicker folderPicker = new FolderPicker();
                folderPicker.SuggestedStartLocation = PickerLocationId.Downloads;
                folderPicker.ViewMode = PickerViewMode.Thumbnail;
                folderPicker.FileTypeFilter.Add("*");
                StorageFolder folder = await folderPicker.PickSingleFolderAsync();
                if (folder != null)
                {
                    StorageFile file = await folder.CreateFileAsync(FileName, CreationCollisionOption.GenerateUniqueName);
                    downloadOperation = backgroundDownloader.CreateDownload(new Uri(url), file);
                    Progress<DownloadOperation> progress = new Progress<DownloadOperation>(progressChanged);
                    cancellationToken = new CancellationTokenSource();
                    
                    try
                    {
                        await downloadOperation.StartAsync().AsTask(cancellationToken.Token, progress);
                    }
                    catch (TaskCanceledException)
                    {
             downloadOperation.ResultFile.DeleteAsync();
                        downloadOperation = null;
                    }
                }
            }
            private void progressChanged(DownloadOperation downloadOperation)
            {
                
                int progress = (int)(100 * ((double)downloadOperation.Progress.BytesReceived / (double)downloadOperation.Progress.TotalBytesToReceive));
                
                switch (downloadOperation.Progress.Status)
                {
                    case BackgroundTransferStatus.Running:
                        {
                            break;
                        }
                    case BackgroundTransferStatus.PausedByApplication:
                        {
                            break;
                        }
                    case BackgroundTransferStatus.PausedCostedNetwork:
                        {
                            break;
                        }
                    case BackgroundTransferStatus.PausedNoNetwork:
                        {
                            break;
                        }
                    case BackgroundTransferStatus.Error:
                        {
                            break;
                        }
                }
                if (progress >= 100)
                {
                    downloadOperation = null;
                }
            }
    
            private void ButtonCancel_Click(object sender, RoutedEventArgs e)
            {
                cancellationToken.Cancel();
                cancellationToken.Dispose();
            }
    
            private void ButtonRefresh_Click(object sender, RoutedEventArgs e)
            {
                Refresh();
            }
        }

    Thursday, April 2, 2015 1:08 PM

Answers

  • Thanks all, I've found a working sample here.

    http://kaki104.tistory.com/category/Windows%208%268.1/Samples?page=2

    Wednesday, April 15, 2015 10:03 AM

All replies

  • Hi skydestiny,

    What is your expected behavior of your app, you mean the app totally cannot binding the progress to the GridView or something like progress does not refresh?

    I saw you have some code like this:

                    downloadOperation = downloads.First();
                    cancellationToken = new CancellationTokenSource();
                    Progress<DownloadOperation> progress = new Progress<DownloadOperation>(progressChanged);
                    ButtonDownload.IsEnabled = false;

    Is that means if there is more than one background task downloading items, the button is disabled, if yes, that also means we only have one items under download per time.

    Besides if you have difficulties on downloading something, you can ref: How to download a file, when I try to repro your code in my project, I found the download does not work, the progress always 0, not sure if that the issue that make the UI not update.

    Anyway, if you have successfully download operation, you can try this for binding latest data to the GridView:

                gv_downloads.ItemsSource = null;
                gv_downloads.ItemsSource = downloads;

    Hope helps,

    --James

    --James


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Friday, April 3, 2015 3:08 AM
    Moderator

  • Hi James,

    For your easy reference, here's my code, http://1drv.ms/1IaYId0

    it's able to download things and reflects its progress in a single progressbar. As shown in the MainPage.xaml, "RED" grid. However, it's unable to show in the "Gray" grid where i place the progressbar and various controls in a gridview's DataTemplate "gv_downloads". I'm not sure what property should i Bind the progressbar to or is there some code behind that i need to make changes to. 



    • Edited by skydestiny Friday, April 3, 2015 5:01 PM
    Friday, April 3, 2015 5:00 PM
  • http://piotrwalat.net/downloading-files-in-windows-8-apps-using-background-transfer-feature/

    You may refer above URL,

    it discuss about

    Downloading files in Windows 8 apps using Background Transfer feature

    Saturday, April 4, 2015 11:53 AM
  • i am trying to bind it to a gridview datatemplate. How can i make the progress bar value changed dynamically?
    Sunday, April 5, 2015 6:08 AM
  • Hi skydestiny,

    That was about MVVM data binding, in total, we need to do following thins:

    #1, use ObservableCollection as the data model because it implement the PropertyChanged event.

    #2, while some of the items changed in the collection, call propertyChanged() to notify the UI refresh.

    If you need more information, you could see https://msdn.microsoft.com/en-us/magazine/jj651572.aspx?utm_source=rss&utm_medium=rss&utm_campaign=mvvm-using-the-mvvm-pattern-in-windows-8 for more information.

    --James


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Wednesday, April 15, 2015 8:28 AM
    Moderator
  • Thanks all, I've found a working sample here.

    http://kaki104.tistory.com/category/Windows%208%268.1/Samples?page=2

    Wednesday, April 15, 2015 10:03 AM
  • Nice to see the shared solution :)

    --James


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Thursday, April 16, 2015 1:58 AM
    Moderator