geospatialwindowsformsintegration

Using ThinkGeo I need select polygon on mouse click and style it - highlight the border - in Windows Forms C#


Is there a simpler, more elegant aproach to select a polygon and highlight it using MapView control from ThinkGeo ?

So far I have implented this approach. On mouse click I add predefined layer to the ThinkGeo MapView Overlay, this layer is a copy of the the "base" layer with all polygons but with only the one polygon on coordinates of the mouse click.


...
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
using ThinkGeo.Core;
using ThinkGeo.UI.WinForms;
...
...
private async void frmFullScreenMaps_Load(object sender, EventArgs e)
{
    this.control.SuspendLayout();
    mapView = new ThinkGeo.UI.WinForms.MapView();
    form.Controls.Add(this.mapView);  // Add the control to the form
    mapView.Location = new System.Drawing.Point(0, 0);
    mapView.MapResizeMode = ThinkGeo.Core.MapResizeMode.PreserveScaleAndCenter;
    mapView.MaximumScale = 1000000D;
    mapView.MinimumScale = 100D;
    mapView.RotatedAngle = 0F; 
    mapView.Size = new System.Drawing.Size(100, 100);
    mapView.Dock = DockStyle.Fill;
    mapView.MapUnit = GeographyUnit.Feet;
    await mapView.RefreshAsync();
    this.control.ResumeLayout(false);
    this.control.PerformLayout();
    ...
    ...  
    // In memory layer - all polygons
    inMemoryFeatureLayer = new InMemoryFeatureLayer();
    ...
    ... 
    // In memory layer - for the (one) selected polygon
    inMemoryHighlighLayer = new InMemoryFeatureLayer();
    //Styling the inMemoryHighlighLayer
    inMemoryHighlighLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = new AreaStyle(new GeoPen(GeoColors.Yellow, 4), new GeoSolidBrush(GeoColors.Transparent));
    inMemoryHighlighLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
    inMemoryHighlighLayer.Open();
    ...
    ...
    // Attach mapView Click event handler
    maps.mapView.MapClick += MapView_MapClick;

    await maps.mapView.RefreshAsync();
}

private async void MapView_MapClick(object sender, MapClickMapViewEventArgs e)
{
    this.tabControlMain.SelectedTab = tabPageMap;
    PointShape clickedPoint = e.WorldLocation;

    // This assume the layer is already open, so we can query it 
    var clickedFeatures = inMemoryFeatureLayer.QueryTools.GetFeaturesContaining(clickedPoint, ReturningColumnsType.NoColumns);

    if (clickedFeatures.Count > 0)
    {
        // Get the clicked feature
        var clickedFeature = clickedFeatures[0];

        // Add the clicked feature to the highlight layer
        inMemoryHighlighLayer.InternalFeatures.Clear();
        inMemoryHighlighLayer.InternalFeatures.Add(clickedFeature);

        // Convert world coordinates to screen coordinates
        var screenPoint = mapView.ToScreenCoordinate(clickedPoint);

        await mapView.RefreshAsync(mapView.CurrentExtent, inMemHighlightOverlay); //zooms to parcel 

    }
    else
    {
        // Clear the highlight layer if no feature was clicked
        inMemoryHighlighLayer.InternalFeatures.Clear();
        await mapView.RefreshAsync();
    }

}
    

Solution

  • Your solution is correct, and probably the 'best' implementation. I know it's a little verbose to create a separate InMemoryFeatureLayer for just one shape, but there is very little performance overhead in the extra layer and it's more flexible having a full layer and more consistent with the api.

    There is an alternative implementation using the MapShape class which will also work if you need different styles on each drawn shape, but in your instance the InMemoryFeatureLayer is probably better.

    Please see below for the MapShape implementation just in case you want to try that route:

    // First Initialize the MapShapesLayer as following: 
    var inMemHighlightOverlay = new LayerOverlay();
    wpfMap.Overlays.Add(inMemHighlightOverlay);
    var mapshapeLayer = new MapShapeLayer();
    inMemHighlightOverlay.Layers.Add(mapshapeLayer);
    
    // Then use the following code to add the feature to highlight
    var mapShape = new MapShape(clickedFeature);
    mapShape.ZoomLevels.ZoomLevel01.DefaultAreaStyle = 
    AreaStyle.CreateSimpleAreaStyle(GeoColors.Red);
    mapShape.ZoomLevels.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
    
    mapshapeLayer.MapShapes.Clear();
    mapshapeLayer.MapShapes.Add("shape1", mapShape);
    await inMemHighlightOverlay.RefreshAsync();