This is a migrated thread and some comments may be shown as answers.

Working with dynamic layers and MapShapeReaders

11 Answers 236 Views
Map
This is a migrated thread and some comments may be shown as answers.
Simon
Top achievements
Rank 1
Simon asked on 28 Oct 2010, 12:33 PM
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

11 Answers, 1 is accepted

Sort by
0
Accepted
Andrey
Telerik team
answered on 01 Nov 2010, 05:08 PM
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
0
Simon
Top achievements
Rank 1
answered on 02 Nov 2010, 09:50 AM
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
0
Accepted
Andrey
Telerik team
answered on 05 Nov 2010, 01:26 PM
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
0
Simon
Top achievements
Rank 1
answered on 05 Nov 2010, 04:46 PM
Brilliant, thanks for looking into this for me

Regards
Simon
0
Thomas
Top achievements
Rank 1
answered on 08 Dec 2010, 05:25 PM
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
0
Andrey
Telerik team
answered on 10 Dec 2010, 06:31 PM
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
0
Gaurav
Top achievements
Rank 1
answered on 28 May 2013, 12:41 PM
How Can I instantiate a MapShapeReader on its own without associating it with a layer in xml side only ??
Is it possible ?
0
Andrey
Telerik team
answered on 29 May 2013, 06:31 AM
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.

0
Gaurav
Top achievements
Rank 1
answered on 29 May 2013, 09:21 AM
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. 
0
Andrey
Telerik team
answered on 29 May 2013, 10:36 AM
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.

0
Gaurav
Top achievements
Rank 1
answered on 29 May 2013, 11:32 AM
Thanks for the quick reply..
Tags
Map
Asked by
Simon
Top achievements
Rank 1
Answers by
Andrey
Telerik team
Simon
Top achievements
Rank 1
Thomas
Top achievements
Rank 1
Gaurav
Top achievements
Rank 1
Share this question
or