0

I have a problem with visualizing the MVVM WPF progress bar. My methods for the main script runs but the progress bar isn't updating at all. I could use tips on getting in the right direction. In my previous codes, I was given tips to use Progress<T> (by @Jonathan Willcock) but I couldn't implement it successfully.

(Please note that this post is not a repeated question because last time, I used button click but I want it to purely be run on data binding)

Question

How do I asynchronously bind the progress bar to the method which is called in my view models? I am using Delegate command to call my methods and I do not want to use the button click event.

What I have in the view - XAML

I have two main functions here, the progress bar and the button. The button starts the method calling successfully but the progress bar doesn't load.

    <ProgressBar Name="pbStatus"
                         Minimum="0"
                         Value="{Binding PrgBarVal, Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"
                         Maximum="100"
                         Height="20"/>
    <Button x:Name = "ApplyButton" Margin="0 1 0 1" Content ="Run software" Command="{Binding RunCalcBtn, Mode=TwoWay}"/>

What I have in the XAML.cs

What I know from the background worker method is that it tries to run it async. I have an issue here, I added a breakpoint here to check if the code runs through the 'Window_ContentRendered' method but it doesn't.

    public partial class UserInterface: UserControl
    {
        public UserInterface()
        {
            InitializeComponent();
        }
        private void Window_ContentRendered(object sender, EventArgs e)
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.DoWork += worker_DoWork; //Do I need a worker.ProgressChanged here?
            worker.RunWorkerAsync();
        }
        thenamespace.ViewModel.SelectedViewModel get = new thenamespace.ViewModel.SelectedViewModel ();
        void worker_DoWork(object sender, DoWorkEventArgs e)
        {

            for (int i = Convert.ToInt32(get.PrgBarVal); i < 100; i++)
            {
                (sender as BackgroundWorker).ReportProgress(i);
            }
        }
    }

What I have in the View Model

In the view model, I am using delegate command to call my data binding methods.

The public SelectedViewModel() is where the Run() method is called. In the Run() method, the functions in there runs correctly and updates the value of PrgBarVal correctly. However, this doesn't update the progress bar at all.

    public class SelectedViewModel : ModelView, INotifyPropertyChanged
    {
        public ModelView modelView { get; set; }

        private DelegateCommand _runCalcBtn;
        public DelegateCommand RunCalcBtn
        {
            get { return _runCalcBtn; }
            set
            {
                _runCalcBtn = value;
                SetPropertyChanged("RunCalcBtn"); //Same as RaisedPropertyChanged
            }
        }
        public SelectedViewModel()
        {
            modelView = new ModelView();
            RunCalcBtn = new DelegateCommand(Run);
        }

        private int _prgBarVal;
        public int PrgBarVal
        {
            get { return _prgBarVal; }
            set
            {
                _prgBarVal = value;
                OnPropertyChanged("PrgBarVal"); //Same as RaisedPropertyChanged
            }
        }

        //Main Function
        private async void Run()
        {

            MethodToWork(); //Function that calls other methods to run 
        }

Thank you very much for your help!

aepot
  • 4,558
  • 2
  • 12
  • 24
Nate
  • 119
  • 1
  • 2
  • 10

1 Answers1

0

Here is the ViewModel (used NuGet ReactiveUI.WPF)

public class MainViewModel : ReactiveObject
{
    private int _workProgress;

    public MainViewModel()
    {
        IProgress<int> progress = new Progress<int>( e => WorkProgress = e );
        StartWork = ReactiveCommand.CreateFromTask( () => ExecuteStartWorkAsync( progress ) );

    }

    private async Task ExecuteStartWorkAsync( IProgress<int> progress )
    {
        progress.Report( 0 );
        for ( int i = 0; i < 1000; i++ )
        {
            await Task.Delay( 10 ).ConfigureAwait( false );
            progress.Report( (int)Math.Floor( i / 1000.0 * 100.0 ) );
        }
    }


    public int WorkProgress { get => _workProgress; private set => this.RaiseAndSetIfChanged( ref _workProgress, value ); }
    public ICommand StartWork { get; }
}

and the View

<Window x:Class="WpfApp4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp4"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Button Content="Start work" Command="{Binding StartWork}" Width="80"/>
            <ProgressBar Value="{Binding WorkProgress,Mode=OneWay}" Width="120"/>
        </StackPanel>
    </Grid>
</Window>
Sir Rufo
  • 18,395
  • 2
  • 39
  • 73