Unable to bind GraphicOverlays collection

1972
10
Jump to solution
11-25-2016 10:49 AM
Highlighted
Occasional Contributor II

I'm currently working on the "old" runtime, and am considering updating to the 100.0 release. I have not yet made the update, but experience a limitation with not being able to bind a graphics collection to GraphicsLayer. It appears I can only add graphics directly from the view, but as my Graphics live in a collection of my viewmodel in the current implementation, it is not very tempting to make the upgrade at the moment. Looking at a few of the Tips & Tricks from the DevSummit 2016, there are several options for making point clustering by implementing an IEnumerable<Graphics>, but I can't see how to do this using the new quartz release. Any suggestions, or expectations that there will be a bindable GraphicsSource on the GraphicsLayer in the near future?

1 Solution

Accepted Solutions
Highlighted
Occasional Contributor II

For anyone who reads this in the future, I'm adding a quick summary of what I did. My main hurdle was that I need the same graphics in multiple maps, which is the main reason for this approach. While I don't know if it is the ideal choice, it works quite well for me:

- GraphicsProvider, as part of the observer pattern (Publish, Delete)

- GraphicsObserver, which observes the provider, and is implemented on a GraphicsOverlay derived class (or operates on graphics overlay to make it cleaner)

- Remember weak references, or at least to call dispose and cleanup if you dispose of a map, otherwise you'll have loads of memory leaks that most likely will frustrate you

- Class deriving from Graphic, in my case MapGraphic. Properties for TargetLayer (and GroupLayer, in my case)

- Synchronise your operation if adding to GraphicsOverlay (as of 100.4) from different threads (Adding Graphic to GraphicsOverlay.Graphics throws ArgumentOutOfRangeException)

- For multiple maps, you might need to create copies of the graphics on add, as they might not want to live in multiple maps, and then update the copies if they already exist

New maps will create GraphicsOverlay with observer, and subscribe to changes from the provider. 

If you don't use multiple maps with the same graphics, you probably don't need this approach, and can do what Morten says above, or see some of the other posts on MVVM in the forums

View solution in original post

Reply
0 Kudos
10 Replies
Highlighted
Frequent Contributor

Thanks for your feedback. While GraphicsOverlay (previously GraphicsLayer) has no GraphicsSource property and its Graphics property is no longer a DependencyProperty, you can use the GraphicsOverlays property in your view model for MapView instead. Rather than working with individual graphics collection, your source will now be collection of graphics overlays.

The following syntax is supported:

<esri:MapView DataContext="{StaticResource viewModel}" GraphicsOverlays="{Binding ResultGraphics}"/>

Reply
0 Kudos
Highlighted
Occasional Contributor II

Thank you for your reply. Wile the suggested solution might work, it feels a little like taking one step back, as the setup of layers and renderers are no longer part of the view, as partially intended by the new design. In addition, it appears like I still won't be able to leverage the clustering, or other filtering mechanism as the Graphics property is read only (referring Point Clustering Tips and Tricks from DevSummit 2016). 

Our application displays one or more maps with Fleet tracking to the user, where the user can see the same information from different scales and extents, in different maps, at the same time. Each map contains a number of different layers with the same graphics, and most of them are dynamic in nature, with varying degree of movement. In the old ArcGIS Runtime SDK for WPF we ended up cloning all graphics, and keeping them up to date, which required a lot of unecessary code, however, we needed this as Graphic could only be added to one layer/map. Before quartz, this was not an issue, as I could bind the same collection to GraphicsLayer. There was one limitation that I had just recently figured out, was to show/hide sub-types of a layer (i.e. show vehicles, but hide helicopters; within the same layer), which was through similar approach as the point cluster sample. In the quartz release, it appears I have now lost the ways of doing the things that I need to do, at least without making the code base a lot bigger. At least with the current requirements.

Is there any chance the GraphicsSource property will be introduced in the next version of the SDK?

These are my wishes

- Bindable collections for GraphicsSource

- Being able to update graphics/attributes without having to switch threads; i.e make it happen in the background/rendering pipeline, where the appropriate dispatcher is available. However, I understand this limitation may be to make the rendering pipeline as fast as possible.

Do you have a link to a roadmap for the product? 

Reply
0 Kudos
Highlighted
Esri Frequent Contributor

Is there any chance the GraphicsSource property will be introduced in the next version of the SDK?

No it won't, but instead think of the GraphicsOverlay as your source/model object. Binding wasn't working correctly to begin with on GraphicsSource, since the property lived on a non-frameworkelement object (GraphicsLayer) and therefore didn't have a datacontext to bind from. It was also UI bound, causing a huge bottleneck, and we want to be able to create these objects on any thread.

Instead we took a cleaner approach and consider the data you put on the MapView (GraphicsOverlays and Map) as the model / viewmodel objects you'd bind onto the MapView. This is better in line with MVVM and causing fewer UI-bound headaches, missing data contexts etc.

Sharing objects among multiple views is something we reluctantly gave up purely for performance and threading stability reasons.

Reply
0 Kudos
Highlighted
Occasional Contributor II

Thank you for the update, even if it was bad news. 

Do you have any suggestions for what I'm trying to accomplish here, without shadow lists, event handlers, and generally hacking a solution for what I want to do?

I suspect I may have to go back to the drawing board to re-think how we work with objects in the map, and how dynamic the information has to be. I was thinking that StreamingLayer would be the next best thing, if not the best, with possibly writing a local service to act as a replacement for the GeoEvent processor. Assuming it doesn't break any license agreements. So far I haven't found any news on when this is available. Also, looking at the API for the Runtime, there are a lot of classes that are internal or sealed, so writing custom layers becomes a bit more work than it used to be in the previous API's. 

Reply
0 Kudos
Highlighted
Occasional Contributor II

For anyone who reads this in the future, I'm adding a quick summary of what I did. My main hurdle was that I need the same graphics in multiple maps, which is the main reason for this approach. While I don't know if it is the ideal choice, it works quite well for me:

- GraphicsProvider, as part of the observer pattern (Publish, Delete)

- GraphicsObserver, which observes the provider, and is implemented on a GraphicsOverlay derived class (or operates on graphics overlay to make it cleaner)

- Remember weak references, or at least to call dispose and cleanup if you dispose of a map, otherwise you'll have loads of memory leaks that most likely will frustrate you

- Class deriving from Graphic, in my case MapGraphic. Properties for TargetLayer (and GroupLayer, in my case)

- Synchronise your operation if adding to GraphicsOverlay (as of 100.4) from different threads (Adding Graphic to GraphicsOverlay.Graphics throws ArgumentOutOfRangeException)

- For multiple maps, you might need to create copies of the graphics on add, as they might not want to live in multiple maps, and then update the copies if they already exist

New maps will create GraphicsOverlay with observer, and subscribe to changes from the provider. 

If you don't use multiple maps with the same graphics, you probably don't need this approach, and can do what Morten says above, or see some of the other posts on MVVM in the forums

View solution in original post

Reply
0 Kudos
Highlighted
Esri Frequent Contributor

This one still has me rather stumped 🙂 I'd need to debug .NET Framework itself to understand why the binding doesn't trigger (everything here smells of a .NET bug), however Microsoft are several patches behind releasing updated symbols for .NET Framework, and you can't really roll back to a .NET version past the one that ships with the Windows install 😞 Once I get .net framework debugging working again, hopefully I can figure out why this happens, but I'm glad you have a workaround for now.

Reply
0 Kudos
Highlighted
Occasional Contributor II

Binding? Referring to the whole message, or the ArgumentOutOfRange part? Or wrong post?

Reply
0 Kudos
Highlighted
Esri Frequent Contributor

Errrr none of it. Sorry long week. Got this one confused with another issue 🙂

Reply
0 Kudos
Highlighted
Occasional Contributor II

Hehe. You and me both. Thought I was the one. Resolving https://community.esri.com/thread/225589-arcgis-runtime-1004-draws-basemap-really-slow-when-zooming-...  would give you a satisfying end of your work week

Reply
0 Kudos