How to update text of ProgressDialog

3143
7
07-24-2018 02:24 PM
stevegourley
Occasional Contributor II

I have a button that shows a progress dialog. I then created a progressor source to update the dialog's message.

                 

                var progress = new ProgressDialog("Creating edit session");

                progress.Show();

                var status = new ProgressorSource(progress);

                status.Progressor.Message = "Test";

                status.Message = "Test2"

Neither of those messages display. It is very difficult to debug since, well, when you debug the dialog is not visible. I'm assuming the progressdialog has it's own internal progresssorsource so mine is being ignored. I assume this because an edit operation is able to update the text of the progressdialog and I did not link the two items together.

What is the proper way to update the progressdialog's message if it is not with the progressor source object?

Tags (2)
0 Kudos
7 Replies
NarelleChedzey
Esri Contributor

Steve, 

take a look at the sample at this location 

arcgis-pro-sdk-community-samples/Framework/ProgressDialog at master · Esri/arcgis-pro-sdk-community-... 

It illustrates using the ProgressDialog with a ProgressSource or a CancellableProgressorSource that updates messages. 

Narelle

0 Kudos
stevegourley
Occasional Contributor II

Thank you for the link, but I reviewed it before posting the question.

It appears to show the progressdialog and the progresssource used separately. It does not show how to use them together which is what I am trying to do. I am also not using the queuetask.run method which is what the sample seems to use the progresssource with.

0 Kudos
NarelleChedzey
Esri Contributor

Steve, 

Try this. 

protected override async void OnClick()
{
  using (var progress = new ProgressDialog("start message", 10))
  {
    var status = new ProgressorSource(progress);

    progress.Show();

    int idx = 0;
    while (idx < 10)
    {
      status.Value += 1;
      status.Message = "Test " + idx.ToString();
      // this works too
      // status.Progressor.Message = "Test " + idx.ToString();
      idx++;

      // do some long running method 
      await QueuedTask.Run(async () =>
      {
        await Task.Delay(1000);
      });
    }

    progress.Hide();
  }

}

0 Kudos
stevegourley
Occasional Contributor II

Good call on the using statement. I didn't realize the progressdialog was disposable.

Here's what I'm trying to do...

I have this command bound to a button.

CreateFacilityCommand.Subscribe(async () => {

                using (var progress = new ProgressDialog("Creating edit session")) {

                    var status = new ProgressorSource(progress);

                    progress.Show();

                    await CreateFacility(status);

                    progress.Hide();

                }

            });

I create the dialog, the progressor source and pass it to an async function.

private async Task CreateFacility(ProgressorSource status) => await QueuedTask.Run(async () => {

            status.Message = "update 1";

      

            var operation = new EditOperation {

                SelectNewFeatures = true,

                ShowProgressor = false,

                ProgressMessage = "Creating new facility",

                ShowModalMessageAfterFailure = true

            };

            status.Message = "update 2";

  

            operation.Create(facilityLayer, attributes);

            await operation.ExecuteAsync();

            if (!operation.IsSucceeded) {

                status.Message = "update 3";

            }

                status.Message = "update 4";

        });

I've tried running on the ui thread, the bg thread, i've tried adding task.delay to slow down the updates, but the text doesn't update.

Do I need to add the number of steps? I don't need accurate progress

0 Kudos
NarelleChedzey
Esri Contributor

You shouldn't have to add the number of steps or increment status.Value

Try adding a 

Task.Delay(1000).Wait(); 

call to block the CIM after every line that updates status.Message. 

Adjust the delay accordingly if 1000 milliseconds is too long. 

0 Kudos
stevegourley
Occasional Contributor II

I tried the task.delay before and it doesn't seem to make any difference.

I was trying to add more UI hints as to what was going on in here uic-addin/CreateNewFacilityControlViewModel.cs at master · agrc/uic-addin · GitHub  with quite a few modifications that aren't shown in that code.

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Hi Steve,

 Sorry - I posted this to one of your other threads accidentally:

 I looked at Narelle's example and at your code (which has changed in the meantime) and I did notice a small difference:

When you call QueuedTask.Run you need to specify the ProgressorSource parameter.  In the snippet I had copied earlier I noticed the missed the parameter: , status.Progressor as you can see here:

private async Task CreateFacilityAsync(ProgressorSource status)
  => await QueuedTask.Run(() =>
  {
  }, status.Progressor);

Also be aware that ProgressorSource status message updates are 'relayed' back to the GUI via a message queue and only processed if the GUI thread gets around to it.  Consequently some messages might be lost because once the GUI processes an update, any subsequent update can 'override' it, if multiple 'backed up' updates are waiting in the message queue.  I think Narelle added the 'Task.Delay' statements to allow the GUI sufficient time to catch up.  In the past I have also used a ProgressBar and Status text fields in my DockPanes to give users a feedback on progress (in some cases that fit my workflow requirements better that a popup dialog).  In this case you need to make sure that any updates to your ViewModule properties are thread save.  Here is a snippet that worked for me (this snippet updates a text property from any thread):

    /// <summary>
    /// UpdateStatusText can be called from any thread to update the TxtStatus
    /// text property in my ViewModel, also adds a newline at the end of the text.
    /// </summary>
    /// <param name="text"></param>
    public void UpdateStatusText(string text)
    {
      if (System.Windows.Application.Current.Dispatcher.CheckAccess())
      {
        TxtStatus += text + Environment.NewLine;
      }
      else
      {
        ProApp.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
          (Action)(() =>
          {
            TxtStatus += text + Environment.NewLine;
          }));
      }
    }

Hope this helps,

Wolf

0 Kudos