0

I am using the following code in WPF application to show progress bar:

XAML:

<Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Button Grid.Row="1" x:Name="btn_StartLengthyTask" Click="btn_StartLengthyTask_Click" Width="200" Height="30" >Start Lengthy Task</Button>
        <ProgressBar Grid.Row="2" x:Name="pb_LengthyTaskProgress" Margin="10,20"  Value="0" ></ProgressBar>
        <TextBlock Grid.Row="3" x:Name="lbl_CountDownTimer" HorizontalAlignment="Center" > 00:10</TextBlock>
        <TextBlock Grid.Row="4" x:Name="lbl_TaskStatus" >Status...</TextBlock>

C#:

private void btn_StartLengthyTask_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                lbl_TaskStatus.Text = "Starting long Task...";
                Thread.Sleep(1000);
                lbl_TaskStatus.Text = "In Progress...";
                pb_LengthyTaskProgress.Value = 0;
                Task.Run(() =>
                {
                    for (int i = 0; i < 100; i++)
                    {
                        Thread.Sleep(50);
                        this.Dispatcher.Invoke(() => //Use Dispather to Update UI Immediately  
                        {
                            var test = OMS.MyOrders.Model.MyOrderExecutor.ExportImages(true);//Method taking long time to response
                            pb_LengthyTaskProgress.Value = i;
                            lbl_CountDownTimer.Text = i.ToString();
                        });
                    }
                });
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

Problem: Progress bar is not updating on UI. Thanks in advance

Sunny
  • 3,185
  • 8
  • 34
  • 66
  • Never call Thread.Sleep. Either use a DispatcherTimer, or an `async` Click event handler that calls `await Task.Delay(...)` in a loop. Dispatcher.Invoke is not needed. – Clemens Apr 27 '23 at 06:04
  • Thanks @Clemens for information. I am new in this process. Could you please update my sample code so I can relate the things. – Sunny Apr 27 '23 at 06:11
  • 1
    Remove `var test = OMS.MyOrders.Model.MyOrderExecutor.ExportImages(true);` out from `Dispatcher.Invoke`, otherwise you process it on GUI thread. – Rekshino Apr 27 '23 at 06:15

1 Answers1

2

Never call Thread.Sleep. Either use a DispatcherTimer, or an async Click event handler that calls await Task.Delay(...) in a loop. Dispatcher.Invoke is not needed. Wrap the long running method in an awaited Task.Run call.

private async void btn_StartLengthyTask_Click(object sender, RoutedEventArgs e)
{
    lbl_TaskStatus.Text = "Starting long Task...";

    await Task.Delay(1000);

    lbl_TaskStatus.Text = "In Progress...";
    pb_LengthyTaskProgress.Value = 0;

    for (int i = 1; i <= 100; i++)
    {
        await Task.Delay(50);

        var test = await Task.Run(() =>
            OMS.MyOrders.Model.MyOrderExecutor.ExportImages(true));

        pb_LengthyTaskProgress.Value = i;
        lbl_CountDownTimer.Text = i.ToString();
    }
}

Update: it seems you only want make a single call to a long running method. The method should then report progress via the IProgress interface:

public bool ExportImages(bool b, IProgress<double> p)
{
    // call p.Report
}

It would be used like this:

private async void btn_StartLengthyTask_Click(object sender, RoutedEventArgs e)
{
    lbl_TaskStatus.Text = "Starting long Task...";
    await Task.Delay(1000);
    lbl_TaskStatus.Text = "In Progress...";

    var progress = new Progress<double>();
    progress.ProgressChanged += (s, p) =>
    {
        pb_LengthyTaskProgress.Value = p;
        lbl_CountDownTimer.Text = p.ToString();
    };

    var result = await Task.Run(() =>
        OMS.MyOrders.Model.MyOrderExecutor.ExportImages(true, progress));
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Clemens, long running method took almost 20 min to process all files. I used your code in my sample application, progress bar is not updating but long running method is in execution in backend. I am able to see updated files. – Sunny Apr 27 '23 at 06:38
  • It should be obvious that there won't be a UI update as long as ExportImages is running. You should split that up into a sequence of method calls that each upload a single image. Otherwise use a ProgressBar that is [indeterminate](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.progressbar.isindeterminate?view=netframework-4.8.1). It is unclear why you have that loop in the first place when you only want do a single ExportImages call. – Clemens Apr 27 '23 at 06:42
  • An alternative would be an ExportImages method that reports progress via the IProgress interface. – Clemens Apr 27 '23 at 06:46
  • I am using progress bar pb_LengthyTaskProgress to update the progress on UI. We can't return progree from Long running method. – Sunny Apr 27 '23 at 06:49
  • So you want to update a ProgressBar from a single long running task that does not report progress. How is that supposed to work? Use an indeterminate ProgressBar. – Clemens Apr 27 '23 at 06:57
  • Yes, you are right only this the way we can show progress. But thanks a lot for making the things clear and you full fill the exact purpose of stackoverflow, to guide the beginners and make interest in the technology. Thanks a lot :-) – Sunny Apr 27 '23 at 07:13