ravi kumar
ravi kumar

Reputation: 1620

Change content of UserControl from Page code behind

So I have a user control:

<StackPanel Orientation="Vertical"
                Margin="10">
        <StackPanel Orientation="Horizontal"
                    HorizontalAlignment="Stretch"
                    Margin="10">
            <TextBlock Text="{x:Bind FileName, Mode=OneTime}"
                       HorizontalAlignment="Left"/>
            <TextBlock Text="{x:Bind DownloadSpeed, Mode=OneWay}" 
                       HorizontalAlignment="Right"/>
        </StackPanel>

        <ProgressBar Name="PbDownload"
                     HorizontalAlignment="Stretch" />

        <TextBlock Text="{x:Bind DownloadCompletePercent, Mode=OneWay}"/>

    </StackPanel>

User control code behind:

public sealed partial class UCDownloadCard : UserControl
    {
        public UCDownloadCard()
        {
            this.InitializeComponent();
        }

        public string FileName { get; set; }
        public string DownloadSpeed { get; set; }
        public string DownloadCompletePercent { get; set; }
    }

What I am trying to do is to show file download status using this user control. Whenever a new download is started, I want to programmatically add a new user control and then update the values in it as the download happens.

Currently I am doing something like this:

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
    }

    public CancellationTokenSource CancellationTokenSource { get; set; }
    public List<DownloadOperation> ActiveDownloads { get; set; } = new List<DownloadOperation>();
    public List<UCDownloadCard> AddedCards { get; set; } = new List<UCDownloadCard>();


    private async Task HandleDownloadAsync(DownloadOperation downloadOperation, CancellationToken cancellationToken = new CancellationToken())
    {
        ActiveDownloads.Add(downloadOperation);
        ...
        ...

        try
        {
            AddDownloadProgressCard();
            await downloadOperation.StartAsync().AsTask(CancellationTokenSource.Token, progressCallback);                
        }

        finally
        {
            ...
            ...
        }
    }

    private void AddDownloadProgressCard()
    {
        var card = new UCDownloadCard
        {
            Name = $"Card{AddedCards.Count}",
            FileName = "Filename.pdf",
            DownloadCompletePercent = "0% completed",
            DownloadSpeed = "0 KB/s"
        };

        AddedCards.Add(card);
        OutputArea.Children.Add(card);
    }

    private void DownloadProgressChanged(DownloadOperation downloadOperation)
    {   
        var downloadPercent = 100 * ((double)downloadOperation.Progress.BytesReceived / (double)downloadOperation.Progress.TotalBytesToReceive);
        this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
        {
            AddedCards[0].DownloadCompletePercent = downloadPercent.ToString();
            Debug.WriteLine($"Updating Progress: {downloadPercent}%");
        });

    }    
}

I am able to add the UserControl to the OutputArea but the values in it are not updating. But I am sure that the AddedCards[0].DownloadCompletePercent = downloadPercent.ToString(); is being executed multiple times because the Debug.WritLine just below it is actually printing to the output window.

How can I update the values in the UserControl ?

Upvotes: 1

Views: 807

Answers (1)

Breeze Liu - MSFT
Breeze Liu - MSFT

Reputation: 3808

Firstly, you should change your UserControl with x:Bind Mode=TwoWay.See {x:Bind} markup extension for more details.

Then you should implement the INotifyPropertyChanged interface and implement the PropertyChanged event. The code you can refer the PropertyChanged event.

Here is a simple sample, you can have a reference.

UserControl.xaml,

<StackPanel Orientation="Vertical"
            Margin="10">
    <StackPanel Orientation="Horizontal"
                HorizontalAlignment="Stretch"
                Margin="10">
    <TextBlock Text="{x:Bind DownloadCompletePercent, Mode=TwoWay}"/>
</StackPanel>

UserControl.xaml.cs,

public sealed partial class UCDownloadCard : UserControl, INotifyPropertyChanged
    {
        public UCDownloadCard()
        {
            this.InitializeComponent();
        }
        private string downloadCompletePercent;
        public string DownloadCompletePercent
        {
            get
            {
                return downloadCompletePercent;
            }
            set
            {
                downloadCompletePercent = value;
                RaisePropertyChanged("DownloadCompletePercent");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }

Then you can add this UserControl and update its downloadCompletePercent,

In the MainPage.xaml.cs,

private void DownloadProgress(DownloadOperation obj)
{
    BackgroundDownloadProgress currentProgress = obj.Progress;
    double percent;
    if (currentProgress.TotalBytesToReceive > 0)
    {
        percent = currentProgress.BytesReceived * 100 / currentProgress.TotalBytesToReceive;
        Debug.WriteLine(percent);
        uCDownloadCard.DownloadCompletePercent = percent.ToString();
    }
}

UCDownloadCard uCDownloadCard;
private void Button_Click_2(object sender, RoutedEventArgs e)
{
    uCDownloadCard = new UCDownloadCard();
    MainPagePanel.Children.Add(uCDownloadCard);
}

Upvotes: 2

Related Questions