Working with dynamic layers and MapShapeReaders

12 posts, 2 answers
  1. Simon
    Simon avatar
    34 posts
    Member since:
    Oct 2010

    Posted 28 Oct 2010 Link to this post

    I have several shape files that define different levels of detail of UK postcodes. They are

    Postcode Area (124 polygons)
    Postcode District (2833 polygons)
    Postcode Sector (9505 polygons)

    If I load them into an InformationLayer then we start to get problems with speed especially on the Postcode Sectors.  I have decided that probably the best approach is to use a Dynamic Layer, and then choose which of the polygons to show.

    I have a couple of questions

    1. Can I instantiate a MapShapeReader on its own without associating it with a layer, and if so, how do I then get the polygons?
    2. Once I have the polygons, is there an easy way to work out which polygons should be displayed?

    I am currently using the beta software with shp files, but I think the basic principal would work with kml files too

    Thanks
    Simon
  2. Answer
    Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 01 Nov 2010 Link to this post

    Hi Simon,

    You can use the MapShapeReader to read shape-file the following way without associating it with a layer:
    private List<FrameworkElement> areas;
      
    private void ReadShapes()
    {
        var reader = new MapShapeReader();
     
        reader.PreviewReadCompleted += new PreviewReadShapesCompletedEventHandler(PreviewReadCompleted);
     
        reader.Read(new Uri("shape-file path", UriKind.RelativeOrAbsolute),
            new Uri("dbf-file path", UriKind.RelativeOrAbsolute));
    }
      
    private void PreviewReadCompleted(object sender, PreviewReadShapesCompletedEventArgs eventArgs)
    {
        if (eventArgs.Error == null)
        {
            this.areas = eventArgs.Items;
        }
    }

    You can use the LocationRect.Intersect method to check if the polygon should be displayed. Also you should check that the polygon has not been added to the dynamic layer earlier.
    Please see the following sample implementation of the dynamic source:
    private class DynamicSource : IMapDynamicSource
    {
        private MainWindow page;
        public DynamicSource(MainWindow examplePage)
        {
            this.page = examplePage;
        }
     
        public void ItemsRequest(object sender, ItemsRequestEventArgs e)
        {
            var layer = sender as DynamicLayer;
     
            double minZoom = e.MinZoom;
     
            Location upperLeft = e.UpperLeft;
            Location lowerRight = e.LowerRight;
            LocationRect rect = new LocationRect(upperLeft, lowerRight);
     
            List<object> items = new List<object>();
     
            if (minZoom == 3)
            {
                // request areas
                foreach (FrameworkElement element in page.areas)
                {
                    var shape = element as MapShape;
                    if (shape != null)
                    {
                        if (this.ShouldBeAdded(rect, shape, layer))
                        {
                            items.Add(shape);
                        }
                    }
                }
            }
     
            e.CompleteItemsRequest(items);
        }
        private bool ShouldBeAdded(LocationRect rect, MapShape shape, DynamicLayer layer)
        {
            return !layer.Items.Contains(shape)
                && rect.Intersect(shape.GeographicalBounds);
        }
    }


    Sincerely yours,
    Andrey Murzov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  3. UI for WPF is Visual Studio 2017 Ready
  4. Simon
    Simon avatar
    34 posts
    Member since:
    Oct 2010

    Posted 02 Nov 2010 Link to this post

    Thanks for the example, it gives me what I need, However working with your shape files it sometimes does not process some of the shapes that I would expect, for example if I use the Europe.shp file, it will never display the united kingdom

    I added the following to the xaml

    <telerik:DynamicLayer x:Name="ThematicLayer">
         <telerik:DynamicLayer.ZoomGridList>
             <telerik:ZoomGrid LatitudesCount="2"
                LongitudesCount="2"
                MinZoom="3" />
             <telerik:ZoomGrid LatitudesCount="4"
                LongitudesCount="4"
                MinZoom="9" />
         </telerik:DynamicLayer.ZoomGridList>
     </telerik:DynamicLayer>

    and then set the DynamicSource of that layer to the DynamicSource object that you gave me

    ThematicLayer.DynamicSource = new DynamicSource(this);

    I then put some debugging into the ShouldBeAdded method and found that for some shapes the Intersect method returned False even when surrounding polygons returned True.

    I then made ShouldBeAdded return True always, and still some shapes would not be rendered

    Attached is a picture of what Europe looks like

    Thanks again for all the help on this

    Simon
  5. Answer
    Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 05 Nov 2010 Link to this post

    Hi Simon,

    Thank you for the information. Indeed, we had a couple problems with using of the map shape objects with DynamicLayer. We've fixed these problems and the fix will be available with 2010.Q3 official release. 

    Sincerely yours,
    Andrey Murzov
    the Telerik team
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
  6. Simon
    Simon avatar
    34 posts
    Member since:
    Oct 2010

    Posted 05 Nov 2010 Link to this post

    Brilliant, thanks for looking into this for me

    Regards
    Simon
  7. Thomas
    Thomas avatar
    2 posts
    Member since:
    Nov 2010

    Posted 08 Dec 2010 Link to this post

    Hi Andrey,

    Is there a way to loop thru the dataSource [dbf file: this.StateLayer.Reader.DataSource = new Uri(string.Format(ShapeRelativeUriFormat, "usa_states.dbf"), UriKind.Relative); ]   prior to it being displayed, I more interested in appending information to the names of state than modifying the names in the dbf file.

    Also, is there a way to load a state map and its counties on startup?

    Regards
    Thomas
  8. Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 10 Dec 2010 Link to this post

    Hi Thomas,

    When the shape reader reads the shape file (shp and dbf pair) then it creates the ExtendedData instance for each shape with a data from dbf file.
    You can change values of properties the ExtendedData provides. Also you can add new property and then assign the value from any other source.
    You can make it from a code for each read shape using the PreviewReadCompleted event. It occurs before the shapes are added to the information layer.
    The sample code is below.
    private const string NonDbfDataField = "SampleDataField"
      
    void RadMap1_InitializeCompleted(object sender, EventArgs e) 
        if (!this.initialized) 
        
            this.initialized = true
      
            this.StateLayer.Reader = new MapShapeReader(); 
            this.StateLayer.Reader.PreviewReadCompleted += new PreviewReadShapesCompletedEventHandler(Reader_PreviewReadCompleted); 
      
            this.StateLayer.Reader.Source = new Uri(string.Format(ShapeRelativeUriFormat, "usa_states.shp"), UriKind.Relative); 
            this.StateLayer.Reader.DataSource = new Uri(string.Format(ShapeRelativeUriFormat, "usa_states.dbf"), UriKind.Relative); 
        
      
    private void Reader_PreviewReadCompleted(object sender, PreviewReadShapesCompletedEventArgs eventArgs) 
        if (eventArgs.Error == null
        
            foreach (MapShape shape in eventArgs.Items) 
            
                this.SetAdditionalData(shape); 
            
        
      
    private void SetAdditionalData(MapShape shape) 
        ExtendedData extendedData = shape.ExtendedData; 
        if (extendedData != null
        
            // add new property to ExtendedData 
            if (!extendedData.PropertySet.ContainsKey(NonDbfDataField)) 
            
                extendedData.PropertySet.RegisterProperty(NonDbfDataField, "", typeof(string), ""); 
            
      
            string stateName = (string)shape.ExtendedData.GetValue("STATE_NAME"); 
            string additionalFieldValue = this.GetDataByStateName(stateName); 
      
            // assign value to new property 
            shape.ExtendedData.SetValue(NonDbfDataField, additionalFieldValue); 
      
            // change existing property 
            shape.ExtendedData.SetValue("STATE_NAME", "State name: " + (string)shape.ExtendedData.GetValue("STATE_NAME")); 
        
      
    private string GetDataByStateName(string stateName) 
        // returns additional field value 

    You can change the StateLayerReaderReadCompleted method of DrillDown example to start loading county information on startup:
    private void StateLayerReaderReadCompleted(object sender, ReadShapesCompletedEventArgs eventArgs) 
        foreach (MapShape shape in this.StateLayer.Items) 
        
            shape.MouseLeftButtonUp += this.StateShapeMouseLeftButtonUp; 
            if ((string)shape.ExtendedData.GetValue("STATE_NAME") == "Texas"
            
                     // setup default state 
                this.stateShape = shape; 
            
        
      
        if (this.stateShape != null
        
            // start loading county information using the MouseLeftButtonUp event handler 
            this.StateShapeMouseLeftButtonUp(this.stateShape, null); 
        

    Best wishes,
    Andrey Murzov
    the Telerik team
    Browse the videos here>> to help you get started with RadControls for WPF
  9. Gaurav
    Gaurav avatar
    35 posts
    Member since:
    Nov 2012

    Posted 28 May 2013 Link to this post

    How Can I instantiate a MapShapeReader on its own without associating it with a layer in xml side only ??
    Is it possible ?
  10. Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 29 May 2013 Link to this post

    Hi Gaurav,

    Yes, it is possible. You can create new instance of the MapShapeReader in the code-behind and then use its Read method to read data without associating it to a layer.
    The sample code is below.
    private void ReadShapes()
    {
        MapShapeReader reader = new MapShapeReader();
      
        reader.PreviewReadCompleted += new PreviewReadShapesCompletedEventHandler(PreviewReadCompleted);
      
        reader.Read(new Uri("shape-file path", UriKind.RelativeOrAbsolute),
            new Uri("dbf-file path", UriKind.RelativeOrAbsolute));
    }
       
    private void PreviewReadCompleted(object sender, PreviewReadShapesCompletedEventArgs eventArgs)
    {
                if (eventArgs.Error != null)
                {
                    MessageBox.Show(eventArgs.Error.Message);
                }
                else
                {
                    // eventArgs.Items contains the list of objects which are created by MapShapeReader
                }
    }

    Regards,
    Andrey Murzov
    Telerik

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  11. Gaurav
    Gaurav avatar
    35 posts
    Member since:
    Nov 2012

    Posted 29 May 2013 Link to this post

    Thanks for ur concern but  i think u didn't get my question..
    I want to do it on code behind... I want to specify datasource and source in the .xml side only.
    BTW i have seen this answer in above post... this is not i want that's why i make a new entry in this thread. 
  12. Andrey
    Admin
    Andrey avatar
    1681 posts

    Posted 29 May 2013 Link to this post

    Hi Gaurav,

    Unfortunately the MapShapeReader cannot be used within XAML code other way than the value of InformationLayer.Reader property. Also it cannot be used for the DynamicLayer in XAML code directly.

    Regards,
    Andrey Murzov
    Telerik

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  13. Gaurav
    Gaurav avatar
    35 posts
    Member since:
    Nov 2012

    Posted 29 May 2013 Link to this post

    Thanks for the quick reply..
Back to Top
UI for WPF is Visual Studio 2017 Ready