Awaiting ListView repaint and Graphics rendering to display progress

1155
3
Jump to solution
05-06-2021 03:29 PM
SunnyG
by
New Contributor

I'm developing a DockPane Add-In that makes searching our API of imagery easy. In short, a Search button is clicked (which issues an ICommand), the search results are retrieved asynchronously from our API and added to a collection bound to a ListView, and an overview geometry graphic is added to the map's GraphicsLayer.

The issue I'm running into is that I want the mouse cursor to be spinning until the ListView is fully re-rendered and the GraphicsLayer is displays the graphic. I thought this would be as simple as awaiting the async steps (API call and the QueuedTask that renders the graphic), but what's currently happening is that the Cursor resets to Default seemingly after the API responds, long before the ListView re-renders and even longer before the GraphicsLayer is updated, especially when hundreds or thousands of results are fetched.

I'm familiar with async/await in JS and Rust, but am pretty new to C#/WPF apps and even newer to ArcGIS Pro SDK so I might be missing the option to await some events or Task configuration.

Is there any way I can create the desired UI experience?

 

 

// the ICommand.Action that is executed on button click
private async void DoSearch()
{
    // Set the cursor to spin, signalling to the user that background work is being done
    Cursor.Current = Cursors.WaitCursor;

    // an ObservableCollection, bound to a ListView in the DockPane
    SearchResults = await StacClient.Instance.SearchItemsEx(request);

    // add search results footprint graphic
    await QueuedTask.Run(() =>
    {
        graphicsLayer.RemoveElements(graphicsLayer.GetElements());

        if (SearchResults.Count > 0)
        {
            graphicsLayer.AddElement(new CIMPolygonGraphic
            {
                Name = "Search Result Overview",
                Symbol = DefaultPolySymbolRef,
                Transparency = DefaultTransparency,
                Polygon = GeometryEngine.Instance.Union(SearchResults.Select(res => res.geometry)) as Polygon,
            });
        }
    });

    // Set the cursor back to the default, signalling the end of search and render
    Cursor.Current = Cursors.Default;
}

 

 

0 Kudos
1 Solution

Accepted Solutions
by Anonymous User
Not applicable

Hi Sunny, 

Given that Pro is asynchronous, what you're looking for given the cursor might be a challenge.  For alternatives, as you may not be able to set the timing required to use the SDK's progress dialog, may want to consider using the circular animation control.  It's used in this community sample in step 15.  

View solution in original post

3 Replies
by Anonymous User
Not applicable

Hi Sunny, 

Given that Pro is asynchronous, what you're looking for given the cursor might be a challenge.  For alternatives, as you may not be able to set the timing required to use the SDK's progress dialog, may want to consider using the circular animation control.  It's used in this community sample in step 15.  

SunnyG
by
New Contributor

Hi @Anonymous User ,

Using the circular animation control worked great - I effectively replaced `Cursor.Current = Cursors.WaitCursor` with `IsSearching = Visibility.Visible`, where `IsSearching` is a class property bound to the control.

For posterity's sake, my guess as to why this works is that it is "hooked" into the same event/animation loop as the rest of the XAML elements (unlike the cursor, which is presumably controlled by the system), and so repainting the circular animation does end up occurring after the list elements and graphics layer finishes re-rendering. If anyone can correct my reasoning, I'm sure everyone would appreciate it 🙂

Thank you!

Wolf
by Esri Regular Contributor
Esri Regular Contributor

Hi Sunny,

 The reason why this works is that ArcGIS Pro supports multi-threading.  You can read more here: ProConcepts Framework / Multithreading · Esri/arcgis-pro-sdk Wiki (github.com).  When you program using the Pro SDK you need to worry only about two threads: The GUI thread (Graphical User Interface thread) and a single specialized worker thread called the Main CIM Thread or MCT.  So if you write code that uses the GUI thread uninterrupted you will see the 'Program not responding' message as used to be the case with ArcMap and ArcObjects.