Simplify Map, MapFrame, Groups and Layers

Developer
Feb 3, 2011 at 5:35 PM

Could we simplify the complex hierarchy of Map, MapFrame, Group and Layers?

The current design of DotSpatial requires writing a recursive function to get the list of all FeatureLayers and RasterLayers (including the layers nested in groups) in my map.

I suggest the following change:

1) Group should not inherit from Layer

2) MapFrame should not inherit from Group

3) Replace the MapFrame.Layers property by two properties: MapFrame.Layers and MapFrame.Groups

4) MapFrame.Layers is the collection of all map layers (including nested layers) . It doesn't include the 'Group' objects

5) MapFrame.Groups is the collection of all groups

6) Layer should have a GroupName property. If GroupName is set, then the legend control displays the layer element as 'nested' in the group element

7) To access the layers nested under a group, use the Group.Layers property

Any thoughts?

Developer
Feb 3, 2011 at 6:29 PM

I'm not currently using groups, but I can see where I might.  I think one advantage of the current architecture is that when the MapFrame code is looping over groups and layers, it doesn't really care whether it is a layer or a group.  This means you can have a group and a layer at the same level in the hierarchy.  In other words, Group A may contain Layer 1 and Group B. The proposed architecture might not make this heterogenous mixing of layers and groups within a group as easy.

I don't think these proposals would cause too much of a perturbation for me, but I've invested a fair amount of work implementing my own Map Layers (derived from Layer and IMapLayer) and MapFrame (derived from MapFrame).  I'd hate to see a huge change in the architecture there.

Kyle

 

Developer
Feb 3, 2011 at 8:02 PM

I think Kyle has a good point.  If you separate out groups from layers, how do you organize your groups and layers on the drawing stack?  For rendering you really do need to be able to have them mixed together in the same list.  Ohterwise you can't easily set up your group of line layers to fall above the polygon layer but below the point layer.  However, I grant you that we certainly could support mechanisms to make it easier for you to do what you describe about cycling through all the non-group layers regardless of depth and cycling through all the groups and child groups and so on.  We could create an IEnumerable property of something like AllLayers on the Map.  This would handle the cycling, but beware, you would not be able to modify this list.  That is, you would not be able to edit the order of the layers in the returned IEnumerable, it would rather be something that would handle the cycling for you.  However, the layer would be the actual layer, so anything you want to do as far as changing the layer itself would work.  We even have built in methods so that the layer can be told to remove itself from the map.  The same is true about Groups or whatever.  It wouldnt' be the master list, but rather would be a read-only IEnumerable that you get handed that is built on the fly from the true list which is of mixed type and handles the casting for you. 

If you need to control positioning within the stack, however, you really need to be working with an entity that can allow both groups and layers to co-exist.  So the master layer that allows you to edit the position and ordering should not be changed to this new design idea I don't think.

Ted

 

 

Developer
Feb 3, 2011 at 8:26 PM

As a side note... this is a great example of me trying to be all things to all people here, and this is where we end up making this too complicated for early users trying to figure out what is what. The above suggestions may not be ideal because it would confuse new developers.  They might get frustrated by the fact that they can't change the order of the "Child" groups in the groups collection because it is read only.  Likewise, they might not understand why they can't simply change the order of two layers in the AllLayers list and have it reflected in the master list which needs to also account for groups and the heirarchy of those groups.  Maybe these added methods are better handled with extension methods.  You can write extension methods that will handle the busy work of cycling for you and the extension methods will appear on the class just like normal methods.  But because they are methods (rather than properties) it will help clarify that these are not the native ordering.  You could name them things like GetGroups() or GetAllLayers().  That way, it may be less confusing.  Also by making them extension methods, you can write the code at any level.  We don't necessarily have to put it in DotSpatial at all.  If this is primarily useful in HydroDekstop, for instance, the methods can be written there, and perform the task as necessary for HydroDesktop code, but without making the existing interfaces any more cluttered and confusing than they already are. 

Anyway, I'm open to shifting things about, but having dealt with the complexities of multiple views on index systems before, I will simply point out that these techniques usually end up being even more confusing than just letting people get to understand the real way elements are stored and work with it directly.  It may be confusing at first, but you are less likely to be frustrated later on if you start off having to learn how the layers are actually stored.

Ted

 

Developer
Feb 3, 2011 at 10:08 PM

Kellison and Ted,

Thank you for your replies. It gives me better understanding of the reasons behind the current MapFrame / Group / Layer architecture.

I still like adding the GetAllLayers() and GetGroups() extension methods. I think these extension methods should be extending the IMap. If there are no objections, I'll go ahead and create the GetAllLayers() and GetGroups() methods in DotSpatial.

I'd also like to have more code examples in the documentation for:

  1. Adding a layer to the map - examples for Feature (vector), Raster and Image
  2. Adding a group to the map
  3. Adding a layer to a group
  4. Moving a layer from one group to another
  5. Changing the order of layers in the legend
  6. Changing the order of groups in the legend
  7. Layer and group events (layer added, group added, layer removed, group removed)

Jiri

 

Coordinator
Feb 3, 2011 at 11:41 PM
Jiri represents our target user. He's GIS savvy, programming savvy, and has used MapWindow stuff in the past. So any suggestions that we can do to make the "Jiri" user's life easier I'm all in favor of. Your suggestions sound good, and I say go for it. As for more examples, well this is something we need all around. Any ideas on how to organize a major new documentation effort on basic activities within DS?


On Thu, Feb 3, 2011 at 4:08 PM, jirikadlec2 <notifications@codeplex.com> wrote:

From: jirikadlec2

Kellison and Ted,

Thank you for your replies. It gives me better understanding of the reasons behind the current MapFrame / Group / Layer architecture.

I still like adding the GetAllLayers() and GetGroups() extension methods. I think these extension methods should be extending the IMap. If there are no objections, I'll go ahead and create the GetAllLayers() and GetGroups() methods in DotSpatial.

I'd also like to have more code examples in the documentation for:

  1. Adding a layer to the map - examples for Feature (vector), Raster and Image
  2. Adding a group to the map
  3. Adding a layer to a group
  4. Moving a layer from one group to another
  5. Changing the order of layers in the legend
  6. Changing the order of groups in the legend
  7. Layer and group events (layer added, group added, layer removed, group removed)

Jiri

Read the full discussion online.

To add a post to this discussion, reply to this email (DotSpatial@discussions.codeplex.com)

To start a new discussion for this project, email DotSpatial@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com




--
Daniel P. Ames, Ph.D. PE
Associate Professor, Geosciences
Idaho State University - Idaho Falls
amesdani@isu.edu
geology.isu.edu
www.mapwindow.org


Developer
Feb 4, 2011 at 9:33 PM
Edited Feb 5, 2011 at 1:38 AM

Currently one has to use a recursive method to handle the LayerAdded (which could be thought of as LayerOrGroupAdded) to perform logic for each added layer.

  
      private void IterateThroughAnyGroupsToFindLayers(ILayer layer)
        {
            MapGroup g = (layer as MapGroup);
            if (g == null)
            {
                // do something here.
            }
            else
            {
                foreach (var l in g.Layers)
                {
                    IterateThroughAnyGroupsToFindLayers(l);
                }
            }
        }


        protected virtual void OnLayerAdded(object sender, LayerEventArgs e)
        {
            IterateThroughAnyGroupsToFindLayers(e.Layers);       
        }

 

Developer
Feb 16, 2011 at 3:45 AM

I have added two new extension methods : Map.GetAllLayers() and Map.GetAllGroups() to the map control and to the IMapFrame. Unit tests for these methods are in DotSpatial.Controls.Tests.MapTest class.

When using these methods, you can access all layers in the map including the nested layers.

While these two methods simplify the coding for DotSpatial users working with groups, I still feel we should think through the MapFrame-Group-Layer-LegendItem architecture and see if the very deep inheritance hierarchy could be simplified.

Jiri

Developer
Feb 19, 2011 at 2:41 PM

Great contribution! It may be worthwhile to replace the

IterateThroughAnyGroupsToFindLayers

method with a call to this extension method.

Developer
Jul 23, 2011 at 3:03 PM

There is one non-obvious behavior with Group,LayerAdded event. I want to handle all  LayerAdded events from all childs (recursively) of current root Group.

Now this event raised only when layers added into root group. To handle event LayerAdded from children now necessary to subscribe to them LayerAdded event manually.

Maybe it make sense to subscribe current group to events of it's children and re-raise events from children to parent recursively?

 

P.S.  I hope, you understand what I mean :)

 

Feb 4, 2013 at 11:24 PM
Check this link page...

TEXT