pjrki
pjrki

Reputation: 248

Progress bars are not updating

I've got a problem with {Binding CurrentProgress} value of Progressbar control inside of a Listview. Within my code I'm able to add few items which has couple of properties with CurrentProgress property as well. Items are adding in a proper way, yet only ONE progressbar's updating. Here's the code:

MODEL:

sealed public class Mp3Model : INotifyPropertyChanged
{
    public string Name { get; set; }

    private double _currentProgress;
    public double CurrentProgress
    {
        get
        {
            return _currentProgress;
        }
        set
        {
            _currentProgress = value;
            OnPropertyChanged("CurrentProgress");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

XAML:

<ListView ItemsSource="{Binding Mp3List}">
    <ListView.View>
        <GridView>
            <GridViewColumn
                Width="140"
                DisplayMemberBinding="{Binding Name}"
                Header="Track Name" />
            <GridViewColumn Width="300" Header="Progress">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Grid Width="320">
                            <ProgressBar
                                Height="40"
                                Margin="10"
                                IsIndeterminate="{Binding IsIndeterminate}"
                                Maximum="100"
                                Minimum="0"
                                Visibility="{Binding IsProgressDownloadVisible}"
                                Value="{Binding CurrentProgress}" />
                            <TextBlock
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                Text="{Binding CurrentProgress, StringFormat={}{0:0}%}"
                                Visibility="{Binding IsPercentLabelVisible}" />
                            <TextBlock
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                Text="{Binding ConvertingLabelText}"
                                Visibility="{Binding IsConvertingLabelVisible}" />
                            <TextBlock
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                Text="{Binding IsOperationDone}"
                                Visibility="{Binding IsOperationDoneLabelVisible}" />
                        </Grid>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

VIEW-MODEL (Method)

private void SaveVideoToDisk()
{
    Task.Factory.StartNew(() =>
    {
        long currentLocalProgress = 0;
        this._fileHelper = new FileHelper();
        this._model = new Mp3Model();

        using (var service = Client.For(YouTube.Default))
        {
            using (var video = service.GetVideo(YoutubeLinkUrl))
            {
                _fileHelper.DefaultTrackName = video.FullName;
                _fileHelper.DefaultTrackPath = _fileHelper.Path + "\\" + _fileHelper.DefaultTrackName;
                _fileHelper.DefaultTrackHiddenPath = _fileHelper.HiddenPath + "\\" + _fileHelper.DefaultTrackName;
                _fileHelper.TmpTrackPath = _fileHelper.PreparePathForFFmpeg(_fileHelper.DefaultTrackHiddenPath);

                _model = new Mp3Model()
                {
                    Name = _fileHelper.DefaultTrackName,
                    IsProgressDownloadVisible = Visibility.Visible,
                    IsPercentLabelVisible = Visibility.Visible,
                    IsConvertingLabelVisible = Visibility.Hidden,
                    IsOperationDoneLabelVisible = Visibility.Hidden,
                    ConvertingLabelText = Consts.ConvertingPleaseWait,
                    CurrentProgress = 0,
                };

                Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                {
                    this._mp3List.Add(_model);
                }));

                using (var outFile = File.OpenWrite(_fileHelper.TmpTrackPath))
                {
                    using (var progressStream = new ProgressStream(outFile))
                    {
                        var streamLength = (long)video.StreamLength();

                        progressStream.BytesMoved += (sender, args) =>
                        {
                            currentLocalProgress = args.StreamLength * 100 / streamLength;
                            _model.CurrentProgress = currentLocalProgress;
                            Debug.WriteLine($"{_model.CurrentProgress}% of video downloaded");
                        };

                        video.Stream().CopyTo(progressStream);
                    }
                }
                //ExtractAudioFromVideo(_fileHelper.TmpTrackPath);
            }
        }
    });
}

Place of the ProgressBar Binded value:

progressStream.BytesMoved += (sender, args) =>
{
    currentLocalProgress = args.StreamLength * 100 / streamLength;
    _model.CurrentProgress = currentLocalProgress;
    Debug.WriteLine($"{_model.CurrentProgress}% of video downloaded");
};

Does anyone has any idea?

Upvotes: 0

Views: 382

Answers (2)

Bruno Belmondo
Bruno Belmondo

Reputation: 2357

Trying to guess: you update a _model field which will be overriden each time you call the save video to disk method. This may only work if only one call of this method can be done by instance of the class (but as we don't have the clas, we don't know if it's the list or the video).

So I would say that invoking twice the method stops the first _model instance from being updated (as the lambda captures the variable holding the object)

Upvotes: 3

Nekeniehl
Nekeniehl

Reputation: 1691

xaml looks okey to me, but I had similar problems, I fixed as follows:

add Mode=OneWay to the Value="{Binding CurrentProgress, Mode=OneWay}".

Also whenever you update CurrentProgress use the Dispatcher: Application.Current.Dispatcher.Invoke(() => CurrentProgress++);

I hope it can helps you to find the solution.

Edit: Just a suggestion, I use the following OnPropertyChanged, so you don't have to write the name of the properties everytime =D.

protected void OnPropertyChange([CallerMemberName] string inPropertyName = null) =>
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(inPropertyName));

Upvotes: -1

Related Questions