Basic map client: Difference between revisions

From Maria GDK Wiki
Jump to navigation Jump to search
()
()
Line 258: Line 258:
Declarations:
Declarations:


<source lang="csharp">public MapViewModel MapViewModel { get; set; }
<source lang="csharp">
public MapViewModel MapViewModel { get; set; }


private IMariaMapLayerManager _mapLayerManager;
private IMariaMapLayer _mapLayer;
private IMariaMapLayer _mapLayer;
private MapLayer _miniMapLayer;</source>
private IMariaMapLayer _miniMapLayer;
 
</source>
 
and in the constructor
and in the constructor


<source lang="csharp">. . .
<source lang="csharp">
. . .


// Service connection specified by app.config
// Service connection specified by app.config
IMariaMapLayerManager mapLayerManager = new MariaMapLayerManager();
_mapLayerManager = new MariaMapLayerManager();
 
_mapLayer = new MapLayer(mapCatalogServiceClient, mapTemplateServiceClient);
_mapLayer = new MapLayer(mapCatalogServiceClient, mapTemplateServiceClient);
_miniMapLayer = new MapLayer(mapCatalogServiceClient, mapTemplateServiceClient);
_miniMapLayer = new MapLayer(mapCatalogServiceClient, mapTemplateServiceClient);
Line 276: Line 281:
Update MariaUserControl binding
Update MariaUserControl binding


<source lang="xml"><MariaUserControl:MariaUserControl Name="MariaCtrl"
<source lang="xml">
<MariaUserControl:MariaUserControl Name="MariaCtrl"
                                   Layers="{Binding Layers}"
                                   Layers="{Binding Layers}"
                                   IsMiniMapVisible="True"
                                   IsMiniMapVisible="True"
Line 286: Line 292:
                                   MiniMapLayer="{Binding MapViewModel.MiniMapLayer}"     
                                   MiniMapLayer="{Binding MapViewModel.MiniMapLayer}"     
                                   />
                                   />
                                                                      </source>
</source>
 
<div class="alert alert-success" role="alert">
<div class="alert alert-success" role="alert">


<i class="fa fa-arrow-circle-right"></i><b> Run:</b><br> Running your application, the window area should now include map information and mini map - and you should be able to navigate the map!
<i class="fa fa-arrow-circle-right"></i><b> Run:</b><br>  
 
Running your application, the window area should now include map information and mini map - and you should be able to navigate the map!


</div>
</div>

Revision as of 17:40, 12 September 2019

This section describes how to create a basic map application, with fixed map type - displaying tracks from a track service.

This example is made to run with Maria GDK Version 4.0.0.x, with .NETFramework 4.6.2.
Sample code for this example is found in the MariaBasicMapClient project of the SampleProjects solution.

Map area with track information

Creating the Map Client Window

Create a WPF Window (main application window or sub window) - MariaWpfWindow - to be used for your map client.
For building Maria GDK clients in Windows forms applications, see Maria Windows-Forms Client.

Creating the map window component

Including MariaUserControl

Add the MariaUserControl to the xaml of your window, name of your choice, optionally including properties for the integrated map controls.

<Window x:Class="BasicMapClient.MariaWpfWindow"
 . . . 
 xmlns:MariaUserControl= "clr-namespace:TPG.Maria.MariaUserControl; assembly=TPG.Maria.MariaUserControl"
 Title="MariaWpfWindow" Height="550" Width="525" >
 <Grid>
 <MariaUserControl:MariaUserControl Name="MariaCtrl"
                                    IsMiniMapVisible="True"
                                    IsPanNavigationVisible="True"
                                    IsScaleBarVisible="True"
                                    IsRulerVisible="True"
                                    />
  </Grid>
</Window>

Main view model

Create a class (MariaWindowViewModel) for communication with the Maria component.

In the constructor of your window (MariaWpfWindow) Set the data context of your client window to be this class.

public MariaWpfWindow()
{
  InitializeComponent();
  DataContext = new MariaWindowViewModel();
}

Handle the WindowClosing event

In the window holding your MariaUserControl (MariaWpfWindow), implement an event handler for the WindowClosing event, disposing the MariaUserControl object and the MapLayerManager object used by the map layers.

In the XAML :

<Window x:Class="BasicMapClient.MariaWpfWindow"
 . . . 
 Title="MariaWpfWindow" Height="550" Width="525" Closing="WindowClosing">
   <Grid>
      <MariaUserControl:MariaUserControl
      . . .

In the code behind:

private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
  MariaCtrl.Dispose();
  ((IDisposable)DataContext).Dispose();
}

Preparing for creation of Maria layers

In the main view model class, MariaWindowViewModel, create an auto property to hold a list of Maria layers, Layers, and add a constructor, initializing the propery.

public ObservableCollection<IMariaLayer>Layers { get; set; }

internal MariaWindowViewModel()
{
    Layers = new ObservableCollection<IMariaLayer>();
}

Then, bind the Layers property of the MariaUserControl to this list.

<MariaUserControl:MariaUserControl Name="MariaCtrl"
                                   Layers="{Binding Layers}"
                                   IsMiniMapVisible="True"
                                   IsPanNavigationVisible="True"
                                   IsScaleBarVisible="True"
                                   IsRulerVisible="True"
                                   />
Empty map with controls

Layer interaction in general

For each of the desired layers (will be described in detail for each layer type):

  • Create an instance of the corresponding GDK layer class
  • Add the created layer to the MariaWindowViewModel Layers property.
  • Create a separate view model class for each layer (may be skipped, if few layers)
  • Add event handler(s) for the LayerInitialized event(s).

The layers are accessed programmatically from your application through the different GDK layer interfaces.


Note:

  • Rendering of the layers will be in the same order as they are in the Layers property.
  • No access should be performed against the layer until the LayerInitialized event has been called.

Service configuration

To enable the service related layers to receive information from their services, they need to establish connections! One way of doing this is by specification in the application configuration (app.config).

Here is a service connection configuration example with connection info for some of the Maria GDK services,within the system.serviceModel tag.
For further details on how to administrate Maria GDK services, refer to the system documentation.

  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="myHttpBinding" 
                 maxBufferSize="2147483647" 
                 maxReceivedMessageSize="2147483647" 
                 closeTimeout="00:10:00" openTimeout="00:10:00" 
                 receiveTimeout="00:10:00" sendTimeout="00:10:00">
          <readerQuotas maxArrayLength="2147483647" />
        </binding>
      </basicHttpBinding>
    </bindings>
    
    <client>
      <!-- Catalog service -->
      <endpoint name="MapCatalogService"
                address="http://localhost:9008/catalog"
                contract="TPG.GeoFramework.MapServiceInterfaces.IMapCatalogService"
                binding="basicHttpBinding"
                bindingConfiguration="myHttpBinding"/>

      <!-- Template service -->
      <endpoint name="TemplateService"
                address="http://localhost:9008/maptemplates"
                contract="TPG.GeoFramework.MapTemplateServiceContracts.IMapTemplateService"
                binding="basicHttpBinding"
                bindingConfiguration="myHttpBinding"/>

      <!-- Track service -->
      <endpoint name="TrackService"
                address="http://localhost:9008/tracks"
                contract="TPG.GeoFramework.TrackServiceInterfaces.IMariaTrackService"
                binding="basicHttpBinding"
                bindingConfiguration="myHttpBinding"/>

      <!-- Enhanced Elevation service -->
      <endpoint name="EnahncedElevationService"
                address="http://localhost:9008/enhancedElevation"
                contract="TPG.EnhancedElevationServiceClient.IEnhancedElevationService"
                binding="basicHttpBinding"
                bindingConfiguration="myHttpBinding"/>

      <!-- Location service -->
      <endpoint name="LocationService"
                address="http://localhost:9008/location/geoloc"
                contract="TPG.GeoFramework.LocationServiceInterfaces.ILocationService"
                binding="basicHttpBinding"
                bindingConfiguration="myHttpBinding"
                behaviorConfiguration="myEndpointBehavior"/>

      <!-- Draw object service -->
      <endpoint name="DrawObjectService"
                address="http://localhost:9008/drawobjects"
                contract="TPG.GeoFramework.DrawObjectServiceInterfaces.IDrawObjectService"
                binding="basicHttpBinding"
                bindingConfiguration="myHttpBinding"/>

      <!-- Geo Fencing Service -->
      <endpoint name="GeoFencingService/DataManager"
                address="http://localhost:9008/GeoFencingService/DataManager"
                contract="TPG.GeoFramework.GeoFencingServiceInterfaces.IDataManagerService"
                binding="basicHttpBinding"
                bindingConfiguration="myHttpBinding" />

      <endpoint name="GeoFencingService/FenceRule"
                address="http://localhost:9008/GeoFencingService/FenceRule"
                contract="TPG.GeoFramework.GeoFencingServiceInterfaces.IGeoFencingRuleService"
                binding="basicHttpBinding"
                bindingConfiguration="myHttpBinding" />

      <endpoint name="GeoFencingService/NotificationHandling"
                address="http://localhost:9008/GeoFencingService/NotificationHandling"
                contract="TPG.GeoFramework.GeoFencingServiceInterfaces.INotificationHandlingService"
                binding="basicHttpBinding"
                bindingConfiguration="myHttpBinding" />

    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="myEndpointBehavior">
          <dataContractSerializer maxItemsInObjectGraph="2147483647" />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <extensions></extensions>
  </system.serviceModel>

Creating a Map Layer with Map Service Connection

The map layer is accessed programmatically through the map layer interface, IMariaMapLayer, and the extended map layer interface IMariaExtendedMapLayer .

  • For this part you will need to include TPG.Maria.MapLayer NuGet package.

Create a view model class (MapViewModel) to handle intaractions toward the map layer, and add the following variables and properties:

private readonly IMariaMapLayer _mapLayer;

public IMariaMapLayer MiniMapLayer { get; set; }
public GeoPos CenterPosition { get; set; }
public double Scale { get; set; }

Create the MapViewModel constructor, initializing map and minimap event handling:

public MapViewModel(IMariaMapLayer mapLayer, IMariaMapLayer miniMapLayer)
{
    _mapLayer = mapLayer;
    _mapLayer.LayerInitialized += OnMapLayerInitialized;
    
    MiniMapLayer = miniMapLayer;
    MiniMapLayer.LayerInitialized += OnMiniMapLayerInitialized;
}

Add the LayerInitialized event handlers for the map and mini map:

private void OnMapLayerInitialized()
{
    Scale = 50000;
    CenterPosition = new GeoPos(60, 10);

    _mapLayer.ActiveMapTemplate = PreferredMapTemplate();
}
private void OnMiniMapLayerInitialized()
{
    MiniMapLayer.ActiveMapTemplate = PreferredMapTemplate();
}

private MapTemplate PreferredMapTemplate()
{
    var preferred = "WorldMap";
    foreach (var template in _mapLayer.ActiveMapTemplates)
    {
        if (template.Name == preferred)
            return template;
    }
    return _mapLayer.ActiveMapTemplates.Any() ? _mapLayer.ActiveMapTemplates.Last() : null;
}

Verify that your app.config file contains endpoint definitions for the MapCatalogService and the TemplateService, as described in the Service Configuration section.

Then, include the MapViewModel in the main view model (MariaWindowViewModel).

Declarations:

public MapViewModel MapViewModel { get; set; }

private IMariaMapLayerManager _mapLayerManager;
private IMariaMapLayer _mapLayer;
private IMariaMapLayer _miniMapLayer;

and in the constructor

. . .

// Service connection specified by app.config
_mapLayerManager = new MariaMapLayerManager();
_mapLayer = new MapLayer(mapCatalogServiceClient, mapTemplateServiceClient);
_miniMapLayer = new MapLayer(mapCatalogServiceClient, mapTemplateServiceClient);

MapViewModel = new MapViewModel(_mapLayer, _miniMapLayer);
Layers.Add(_mapLayer);

Update MariaUserControl binding

<MariaUserControl:MariaUserControl Name="MariaCtrl"
                                   Layers="{Binding Layers}"
                                   IsMiniMapVisible="True"
                                   IsPanNavigationVisible="True" 
                                   IsScaleBarVisible="True" 
                                   IsRulerVisible="True" 
                                   CenterScale="{Binding MapViewModel.Scale}" 
                                   CenterPosition="{Binding MapViewModel.CenterPosition}" 
                                   MiniMapLayer="{Binding MapViewModel.MiniMapLayer}"     
                                   />
Map area with map information

Creating Track Layer with Track Service Connection

Key information:

  • The track layer is accessed programmatically through the track layer interface IMariaTrackLayer and the extended track layer interface IMariaExtendedTrackLayer.
  • For this part you will need to add the TPG.Maria.TrackLayer NuGet package.

Create a view model class (TrackViewModel) for the track layer:

public class TrackViewModel 
{    
}

Add the following local variable

private readonly IMariaTrackLayer _trackLayer;

Add the TrackViewModel constructor

public TrackViewModel(IMariaTrackLayer trackLayer)
{
    _trackLayer = trackLayer;
    _trackLayer.LayerInitialized += OnTrackLayerInitialized;
}

Implement the OnInitialized event handler (OnTrackLayerInitialized) For the TrackList value, use a track list available in your Track Service.

private void OnTrackLayerInitialized()
{  
    _trackLayer.TrackLists = new ObservableCollection<string> { "ais.test" };
    _trackLayer.TrackServices = new ObservableCollection<IMariaService> 
          {
              new MariaService("TrackService")
          };

    if (_trackLayer.TrackServices.Count > 0)
    {
        _trackLayer.ActiveTrackService = _trackLayer.TrackServices[0];
        _trackLayer.ActiveTrackList = _trackLayer.TrackLists[0];
    }
}

Make sure that your app.config file contains endpoint definitions for the TrackService, as described in the Service Configuration section.

Then, include the TrackViewModel in the main view model (MariaWindowViewModel).

Declarations:

private readonly IMariaTrackLayer _trackLayer;
public TrackViewModel TrackViewModel { get; set; }

and in the constructor

_trackLayer = new TPG.Maria.TrackLayer.TrackLayer();
TrackViewModel = new TrackViewModel(_trackLayer);
Layers.Add(_trackLayer);


Run: In addition to map information and mini map, the application should now include tracks from the specified track list of a Track Service, and you should be able to select tracks!

Map area with track information