3

I'm developing a "search tool" dockpane in the ArcGIS Pro SDK using MVVM. I have a button on my dockpane hooked up to a relaycommand in my viewmodel, which trys to call an async method in my model to return a list of results:

    /// <summary>
    /// Search results 
    /// </summary>
    private ObservableCollection<string> _searchResults = new ObservableCollection<string>(); 
    public IList<string> SearchResults
    {
        get { return _searchResults; }
    }

    /// <summary>
    /// Search button command
    /// </summary>
    private ICommand _searchCommand;
    public ICommand SearchCommand
    {
        get
        {
            _searchCommand = new RelayCommand(
                async() =>
                {
                    SearchResults.Clear();
                    var results = await DockFindModel.SearchAsync(_selectedSearchableLayer, _searchString);
                    foreach (var item in results)
                    {
                        SearchResults.Add(item);
                    }                    
                    //notify results have changed
                    NotifyPropertyChanged(() => SearchResults);
                },
                () => bAppRunning); //command will only execute if app is running
            return _searchCommand;
        }
    }

However I get the following exception when the relaycommand tries to execute:

An unhandled exception of type 'System.AggregateException' occurred in mscorlib.dll

Additional information: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread.

I've tried a number of things in this thread to try and resolve the issue with no luck. I'm sure running aync methods in a relaycommand is pretty fundamental to the ArcGIS Pro SDK as ESRI recommend you use MVVM, plus a lot of the supplied methods must be ran asynchronously.

Anyone have luck with this?

2

The QueuedTask class is used instead of the Task class for the following reasons:

Queuing and concurrency control

When Tasks are dispatched using Task.Run, the associated Task will execute on a random thread in the managed thread pool each time it’s called. If a subsequent call to Task.Run is called from anywhere else in the application, the new Task will start running immediately on yet another thread—potentially while the first Task is still running on the first thread. Going back to the list of challenges inherent in multithreaded code, it should be obvious that executing unorganized operations concurrently is likely to lead to crashes and corruption of application state. The queuing behavior of QueuedTask.Run ensures the proper ordering of calls and reduces the risk of conflicts. Remember that the parallelism going on within ArcGIS Pro is accomplished internally; this simplifies the public programming model and greatly reduces the likelihood of conflicts.

Affinity and state

For performance reasons, ArcGIS Pro maintains considerable state on specific threads and in many cases, uses objects that have thread affinity. Thread affinity means that an object is tied to a particular thread and should not be interacted with from any thread but the thread it has affinity with. Affinity constraints are common in operating systems and components, including database connections, windows, controls, input queues, timers, WPF Bitmaps, and COM servers. In WPF for example, calling methods on any object derived from the WPF DependencyObject class will result in an exception if the call is made from a thread the object wasn’t created on.

Threads in the managed thread pool are also incompatible with most COM components, so you should not attempt to use Task.Run with code that might execute COM components directly or indirectly.

Application integration

When Tasks are dispatched using QuededTask.Run, they are automatically integrated with various features within the application as follows:

•The extended Progress/Cancelation framework where progress, including the programmable progress dialog, is displayed and hidden automatically and where cancellation state is properly communicated between relevant parts of the application.

•The application busy state system where UI elements such as buttons and tools are automatically enabled and disabled when Tasks are running. Task execution can also be coordinated with critical phases such as view creation and application shutdown.

•Queued Tasks are enlisted in the framework’s diagnostic facilities, when enabled. This lets developers monitor the sequence of running Tasks, the functions Tasks are executing, and the duration of execution. This kind of information is invaluable in debugging and performance analysis.

Acceptable cases for using Task.Run

There are cases where the use of Task.Run is acceptable—such as when executing independent background operations consisting entirely of managed code—so long as the particular managed components in use do not have thread affinity. The developer takes full responsibility for handling cancellation, displaying progress, enabling/disabling the UI appropriately, coordinating operations, and handling logical conflicts

1

Ok so I managed to resolve the issue by making a change to the way I run my async method.

I changed this:

var results = await DockFindModel.Search();

To this:

var results = await QueuedTask.Run(() => DockFindModel.Search());

Although i'm a bit confused as to why I need to await Task.Run() when relaycommand is already accepting async lambda. I'm sure it'll become clear with time however.

0

Concurrency is one of the issues to address when running code in parallel. The synchronization could be a simple lock() on an object (but not this) and there are good reason where to queue execution, but concurrency and crashes are not one of them. Queuing is still sequential, so for parallel execution you just have to learn to handle it instead of avoiding it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.