<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Incrementing progress bar on dock panel from external class function in ArcGIS Pro SDK Questions</title>
    <link>https://community.esri.com/t5/arcgis-pro-sdk-questions/incrementing-progress-bar-on-dock-panel-from/m-p/1203746#M8605</link>
    <description>&lt;P&gt;Hello all,&lt;/P&gt;&lt;P&gt;I've been trying to implement a progress bar on a dock pane that increments as a function in a separate class downloads a list of GeoTiffs using HttpClient.&lt;/P&gt;&lt;P&gt;I've successfully got this to work using the approach provided in the code sample Overlay3D.&lt;/P&gt;&lt;P&gt;However, unlike this example, my list of tasks I want to increment occurs in a separate function outside of the dock pane, and I'm not sure how to pass the information from that function back to the dock pane.&lt;/P&gt;&lt;P&gt;Any advice is welcome. I have provided a cut down code example below of my current setup, the comments should show where I am getting stuck:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;XAML progress bar&lt;/STRONG&gt;, with two bindings (MaxProgressValue and Progress Value) back to dock pane view model.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="markup"&gt;&amp;lt;!-- Progress bar--&amp;gt;
&amp;lt;ProgressBar Name="PrgProgressBar" 
             Grid.Column="0"
             Margin="0,0,5,0"  
             Height = "10"
             HorizontalAlignment="Stretch"
             Minimum="1"
             Maximum="{Binding Path=MaxProgressValue, Mode=OneWay}"
             Value="{Binding Path=ProgressValue, Mode=OneWay}"  
             IsIndeterminate="False"&amp;gt;
&amp;lt;/ProgressBar&amp;gt;&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;ViewModel&lt;/STRONG&gt; related to progress bar, with a button to call a function to download geotiffs.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;// Getter, Setter for progress bar
private double _maxProgressValue = 100;
public double MaxProgressValue
{
  get { return _maxProgressValue; }
  set { SetProperty(ref _maxProgressValue, value, () =&amp;gt; MaxProgressValue); }
}

// Update progress bar method (based on Overlay3D)
private int _iProgressValue = -1;
private int _iMaxProgressValue = -1;
private void ProgressUpdate(int iProgressValue, int iMaxProgressValue)
{
  if (System.Windows.Application.Current.Dispatcher.CheckAccess())
  {
    if (_iMaxProgressValue != iMaxProgressValue)
    {
      MaxProgressValue = iMaxProgressValue;
    }

    if (_iProgressValue != iProgressValue)
    {
      ProgressValue = iProgressValue;
    }
  }
  else
  {
    ProApp.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)(() =&amp;gt; {
    if (_iMaxProgressValue != iMaxProgressValue)
    {
      MaxProgressValue = iMaxProgressValue;
    }
    if (_iProgressValue != iProgressValue)
    {
      ProgressValue = iProgressValue;
    }
    }));
  }
}

// Button on dock panel to run download function
public ICommand CmdRun
{
  get
    {
      return new RelayCommand(async () =&amp;gt;
        {
          // Excluded various things
          // ...
 
          // Initialise data structure STAC that contains urls and functions
          Stac stac = new Stac(...)

          // Reset progressor value and maximum value
          ProgressUpdate(1, stac.Result.Features.Count);

          // Start queued task and download geotifs
          await QueuedTask.Run(() =&amp;gt; 
          {
            // Begin download tifs loop
            // How do I monitor progession? 
            // Pass a progressor variable via IProgress?
            await stac.DownloadFeaturesAsync(assets, outputFolder);
          });
        }
      }&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;STRONG&gt;Stac&lt;/STRONG&gt; class for DownloadFeatureAsync.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="cpp"&gt;public async Task DownloadFeaturesAsync(List&amp;lt;string&amp;gt; assetNames, string outputFolder)
{
  // Some uninteresting work...
  // ...
  
  // Iterate dates in STAC query and download tif to folder
  foreach (string date in dates)
  {
    // Open a HTTP client
    var client = new HttpClient();

    // Create a list of downloader tasks
    int i = 0; // test
    var tasks = new List&amp;lt;Task&amp;gt;();
    foreach (var item in items)
    {
      string date = item.Key;
      string url = item.Value[0];
      string filename = item.Value[1];

      tasks.Add(Task.Run(async () =&amp;gt;
      {
        // Do some things...

        // Query URL and ensure success
        var response = await client.GetAsync(url);
        response.EnsureSuccessStatusCode();

        // Download file to output folder
        using (FileStream fs = new FileStream(filepath, FileMode.CreateNew))
        {
          await response.Content.CopyToAsync(fs);
        }

        // Increment progress bar... how...?!
        // ...
      }));
    }

  // Run all download tasks
  await Task.WhenAll(tasks);
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Wed, 17 Aug 2022 14:50:48 GMT</pubDate>
    <dc:creator>LewisTrotter</dc:creator>
    <dc:date>2022-08-17T14:50:48Z</dc:date>
    <item>
      <title>Incrementing progress bar on dock panel from external class function</title>
      <link>https://community.esri.com/t5/arcgis-pro-sdk-questions/incrementing-progress-bar-on-dock-panel-from/m-p/1203746#M8605</link>
      <description>&lt;P&gt;Hello all,&lt;/P&gt;&lt;P&gt;I've been trying to implement a progress bar on a dock pane that increments as a function in a separate class downloads a list of GeoTiffs using HttpClient.&lt;/P&gt;&lt;P&gt;I've successfully got this to work using the approach provided in the code sample Overlay3D.&lt;/P&gt;&lt;P&gt;However, unlike this example, my list of tasks I want to increment occurs in a separate function outside of the dock pane, and I'm not sure how to pass the information from that function back to the dock pane.&lt;/P&gt;&lt;P&gt;Any advice is welcome. I have provided a cut down code example below of my current setup, the comments should show where I am getting stuck:&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;XAML progress bar&lt;/STRONG&gt;, with two bindings (MaxProgressValue and Progress Value) back to dock pane view model.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="markup"&gt;&amp;lt;!-- Progress bar--&amp;gt;
&amp;lt;ProgressBar Name="PrgProgressBar" 
             Grid.Column="0"
             Margin="0,0,5,0"  
             Height = "10"
             HorizontalAlignment="Stretch"
             Minimum="1"
             Maximum="{Binding Path=MaxProgressValue, Mode=OneWay}"
             Value="{Binding Path=ProgressValue, Mode=OneWay}"  
             IsIndeterminate="False"&amp;gt;
&amp;lt;/ProgressBar&amp;gt;&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;ViewModel&lt;/STRONG&gt; related to progress bar, with a button to call a function to download geotiffs.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;// Getter, Setter for progress bar
private double _maxProgressValue = 100;
public double MaxProgressValue
{
  get { return _maxProgressValue; }
  set { SetProperty(ref _maxProgressValue, value, () =&amp;gt; MaxProgressValue); }
}

// Update progress bar method (based on Overlay3D)
private int _iProgressValue = -1;
private int _iMaxProgressValue = -1;
private void ProgressUpdate(int iProgressValue, int iMaxProgressValue)
{
  if (System.Windows.Application.Current.Dispatcher.CheckAccess())
  {
    if (_iMaxProgressValue != iMaxProgressValue)
    {
      MaxProgressValue = iMaxProgressValue;
    }

    if (_iProgressValue != iProgressValue)
    {
      ProgressValue = iProgressValue;
    }
  }
  else
  {
    ProApp.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (Action)(() =&amp;gt; {
    if (_iMaxProgressValue != iMaxProgressValue)
    {
      MaxProgressValue = iMaxProgressValue;
    }
    if (_iProgressValue != iProgressValue)
    {
      ProgressValue = iProgressValue;
    }
    }));
  }
}

// Button on dock panel to run download function
public ICommand CmdRun
{
  get
    {
      return new RelayCommand(async () =&amp;gt;
        {
          // Excluded various things
          // ...
 
          // Initialise data structure STAC that contains urls and functions
          Stac stac = new Stac(...)

          // Reset progressor value and maximum value
          ProgressUpdate(1, stac.Result.Features.Count);

          // Start queued task and download geotifs
          await QueuedTask.Run(() =&amp;gt; 
          {
            // Begin download tifs loop
            // How do I monitor progession? 
            // Pass a progressor variable via IProgress?
            await stac.DownloadFeaturesAsync(assets, outputFolder);
          });
        }
      }&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;STRONG&gt;Stac&lt;/STRONG&gt; class for DownloadFeatureAsync.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="cpp"&gt;public async Task DownloadFeaturesAsync(List&amp;lt;string&amp;gt; assetNames, string outputFolder)
{
  // Some uninteresting work...
  // ...
  
  // Iterate dates in STAC query and download tif to folder
  foreach (string date in dates)
  {
    // Open a HTTP client
    var client = new HttpClient();

    // Create a list of downloader tasks
    int i = 0; // test
    var tasks = new List&amp;lt;Task&amp;gt;();
    foreach (var item in items)
    {
      string date = item.Key;
      string url = item.Value[0];
      string filename = item.Value[1];

      tasks.Add(Task.Run(async () =&amp;gt;
      {
        // Do some things...

        // Query URL and ensure success
        var response = await client.GetAsync(url);
        response.EnsureSuccessStatusCode();

        // Download file to output folder
        using (FileStream fs = new FileStream(filepath, FileMode.CreateNew))
        {
          await response.Content.CopyToAsync(fs);
        }

        // Increment progress bar... how...?!
        // ...
      }));
    }

  // Run all download tasks
  await Task.WhenAll(tasks);
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 17 Aug 2022 14:50:48 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-pro-sdk-questions/incrementing-progress-bar-on-dock-panel-from/m-p/1203746#M8605</guid>
      <dc:creator>LewisTrotter</dc:creator>
      <dc:date>2022-08-17T14:50:48Z</dc:date>
    </item>
    <item>
      <title>Re: Incrementing progress bar on dock panel from external class function</title>
      <link>https://community.esri.com/t5/arcgis-pro-sdk-questions/incrementing-progress-bar-on-dock-panel-from/m-p/1203768#M8608</link>
      <description>&lt;P&gt;You can define a reference to your view model in your Module.&amp;nbsp; Since the Module class is a singleton you can then use that reference from your external class.&amp;nbsp; Look at this example:&amp;nbsp;&amp;nbsp;&lt;A href="https://github.com/esri/arcgis-pro-sdk-community-samples/tree/master/Map-Exploration/MapToolIdentifyWithDockpane" target="_blank"&gt;arcgis-pro-sdk-community-samples/Map-Exploration/MapToolIdentifyWithDockpane at master · Esri/arcgis-pro-sdk-community-samples (github.com)&lt;/A&gt;&lt;/P&gt;&lt;P&gt;in this sample the reference to the view modal is defined in the Module class as follows:&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;internal static MapToolIdentifyDockpaneViewModel MapToolIdentifyDockpaneVM { get; set; }&lt;/LI-CODE&gt;&lt;P&gt;In the Ctor of the view model that 'global accessible' reference is initialized:&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;protected MapToolIdentifyDockpaneViewModel()
{
  // register self with Module class
  Module1.MapToolIdentifyDockpaneVM = this;
}&lt;/LI-CODE&gt;&lt;P&gt;And it is then used in an external class (the tool in this case) here (&lt;A href="https://github.com/Esri/arcgis-pro-sdk-community-samples/tree/master/Framework/DockpaneSimple" target="_self"&gt;https://github.com/Esri/arcgis-pro-sdk-community-samples/tree/master/Framework/DockpaneSimple&lt;/A&gt;&amp;nbsp;&lt;span class="lia-unicode-emoji" title=":disappointed_face:"&gt;😞&lt;/span&gt;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;protected override async Task&amp;lt;bool&amp;gt; OnSketchCompleteAsync(Geometry geometry)
{
  Module1.MapToolIdentifyDockpaneVM.ClearListOfFeatures();
  await QueuedTask.Run(() =&amp;gt;
  {
    Module1.MapToolIdentifyDockpaneVM.AddToListOfFeatures($@"Layer: {featLyr.Name} obj id: {feat.GetObjectID()} Display Expression: {displayExp}");
  });
  return true;
}&lt;/LI-CODE&gt;&lt;P&gt;If you call your progressbar updates from a background thread, you might want to consider the following method that ensure execution on the UI thread (sample: &lt;A href="https://github.com/Esri/arcgis-pro-sdk-community-samples/blob/master/Framework/DockpaneSimple/BookmarkDockpaneViewModel.cs#L104" target="_self"&gt;arcgis-pro-sdk-community-samples/Map-Exploration/MapToolIdentifyWithDockpane at master · Esri/arcgis-pro-sdk-community-samples (github.com)&lt;/A&gt;&lt;span class="lia-unicode-emoji" title=":disappointed_face:"&gt;😞&lt;/span&gt;&lt;/P&gt;&lt;LI-CODE lang="csharp"&gt;/// &amp;lt;summary&amp;gt;
/// utility function to enable an action to run on the UI thread (if not already)
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name="action"&amp;gt;the action to execute&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
internal static Task RunOnUIThread(Action action)
{
    if (OnUIThread)
    {
        action();
        return Task.FromResult(0);
    }
    else
        return Task.Factory.StartNew(action, System.Threading.CancellationToken.None, TaskCreationOptions.None, QueuedTask.UIScheduler);
}

/// &amp;lt;summary&amp;gt;
/// determines if the application is currently on the UI thread
/// &amp;lt;/summary&amp;gt;
private static bool OnUIThread
{
    get
    {
        if (FrameworkApplication.TestMode)
            return QueuedTask.OnWorker;
        else
            return System.Windows.Application.Current.Dispatcher.CheckAccess();
    }
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 17 Aug 2022 15:23:05 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-pro-sdk-questions/incrementing-progress-bar-on-dock-panel-from/m-p/1203768#M8608</guid>
      <dc:creator>Wolf</dc:creator>
      <dc:date>2022-08-17T15:23:05Z</dc:date>
    </item>
    <item>
      <title>Re: Incrementing progress bar on dock panel from external class function</title>
      <link>https://community.esri.com/t5/arcgis-pro-sdk-questions/incrementing-progress-bar-on-dock-panel-from/m-p/1204943#M8618</link>
      <description>&lt;P&gt;Thanks Wolf,&lt;/P&gt;&lt;P&gt;I ended up using IProgress to increment my progress bar. Basically, I associate my ProgressValue (which is bound to UI) with IProgress, and then just use progress.Report(i) within my button RelayCommand logic to increment it. Seems to work perfectly.&lt;/P&gt;&lt;P&gt;Do you think this is a valid approach?&lt;/P&gt;</description>
      <pubDate>Mon, 22 Aug 2022 12:04:09 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-pro-sdk-questions/incrementing-progress-bar-on-dock-panel-from/m-p/1204943#M8618</guid>
      <dc:creator>LewisTrotter</dc:creator>
      <dc:date>2022-08-22T12:04:09Z</dc:date>
    </item>
  </channel>
</rss>

