1

I have a listbox with items and the user can perform some actions on an item, such as New/Edit/Delete. However, this can take some time, and I would like to show an indeterminate progressbar while the underlying actions are being performed.

How should I handle this in .NET 4.6 & C# 6.0? According to this post I should be using Task-based Asynchronous Pattern (TAP). In the thread there are many many possible solutions.

Is that still the preferred way?

Community
  • 1
  • 1
Igavshne
  • 699
  • 7
  • 33

2 Answers2

1

The first thing to understand here is that you should perform the New/Edit/Delete operations on a background thread in order to keep your UI responsive and for the ProgressBar to be able to update during the time it takes for these operations to complete.

The preferred and easiest way to off-load some work to a background thread is to use the task parallel library (TPL) and start a new task. Keep in mind that WPF controls have thread affinity though so you can only access them on the thread on which they were originally created and that is the dispatcher thread.

So you could implement this by setting the Visibility property of the ProgressBar to Visible, start a task that performs the actual New/Edit/Delete operation and then set the Visibility property back to Collapsed again once the task has finished:

C#:

pb.Visibility = Visibility.Visible;
Task.Run(()=> 
{
    //perform your long-running operation here...make sure that you don't access any UI elements
    Save();
})
.ContinueWith(task => 
{
    //this delegate will be executed back on the UI thread once the task has finished because of the scheduler returned from the TaskScheduler.FromCurrentSynchronizationContext() method...
    pb.Visibility = Visibility.Collapsed;
}, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

XAML:

<ProgressBar x:Name="pb" IsIndeterminate="True" Visibility="Collapsed" />
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Would the C# that you gave above typically be in the xaml.cs file? I have the New/Edit/Delete functionality in my ViewModel and it is "accessed" via Commands. I'm very new with WPF and MVVM, and I just try to find the best practices of doing things, but I'm not very competent on my own. Also, with the Delete for instance, I delete the item out of the listbox (obviously a UI element) and also from the solution explorer (I'm busy with a VS package extension) and this last one takes a couple of seconds. So I'm not sure how I should not access a UI element like you have stated? – Igavshne Feb 06 '17 at 18:22
  • The New/Edit/Delete functionality should be implemented in the view model. Instead of setting the Visibility property of the ProgressBar directly you set the value of a source property that you bind to the ProgressBar. I guess your operations actually perform some work that may take some time, for example communicating with a database or service layer. If you simply want to remove an item from a ListBox, or rather the ObservableCollection that is bound to the ListBox, you won't need a ProgressBar at all. – mm8 Feb 06 '17 at 20:55
  • Ah yes, of course, I can set the value of a source property that is bound to the ProgressBar. Yes, I do have communication with a DB. Thanks, I'll try your answer and then come back. – Igavshne Feb 07 '17 at 12:40
0

in C# you can use progressBar tool from toolbox to show indeterminate time.

In order to use the progressBar just drag and drop it on your form.

Now coming to main problem, you want show an indeterminant time. To show the progress in progressBar, use timer and following code:

int value = 0;
private void timer1_Tick(object sender, EventArgs e)
    {
        if (value < 100)//value at 100 can be any large integer since indeterminant time
        {
            value++;
            progressBar1.Value = value;
        }

    }

set timer1.Interval = 100;

variable value is the maximum value you set for progressBar.

Since you dont know the time, set the maximum value of progressBar to 10000 or any other big value. Now enable the timer when you enter your function(say New/Edit/Delete) and disable the timer when you exit your function

Raj Kumar Mishra
  • 516
  • 4
  • 16
  • I don't like this solution. You are just "cheating" the progress bar value. Instead, one can use the Indeterminate property of a progress bar as pointed in an answer by @mm8. – Kamil Solecki Feb 04 '17 at 14:09
  • It may be cheating but that will work. Now the main thing is that you are not telling the user exact amount of time application takes to complete these tasks, hence indeterminant time. So according to me you need not show the progress bar at 100% when the tasks are completed by the application. – Raj Kumar Mishra Feb 04 '17 at 20:23
  • I do not think this is good programming practice. Whoever has to maintain the code after me will surely waste time trying to figure out what is going on. – Igavshne Feb 06 '17 at 18:12
  • A simple comment such as what? Give me an example of what you would say about the code above. – Igavshne Feb 07 '17 at 12:44
  • @RAJKUMARMISHRA, your solution probably works, but in the much bigger picture, I would like to ask you in a polite way to take some time and think about your style of programming. It seems that you are in the habit of just getting things "to work", -by hook or by crook. Short-term, all seems well, but long term it will sink you and your reputation. Read some books about design and programming practice. Learn to code at a high standard, so that you feel proud of what you have created. Do it well the the first time even if it takes a bit longer, because it saves so much time later! – Igavshne Feb 16 '17 at 14:09
  • I'm thankful for your advice and will surely look into it. No hard feelings. – Raj Kumar Mishra Feb 16 '17 at 16:18