Display SQLite Data in WPF

SQLite is a local file-based database that uses a single file that can store anything in our case we can use it to store features, shapes and geometrical data.

Project Setup

We will start off by creating a new project in Visual Studio 2019. You can use the first few steps in Microsoft's guide to Create a WPF Application on their documentation website. Once the project is opened in Visual Studio, you are ready to move on to the next step.

Installing NuGet Packages

In order to display our SQLite data on a map, we will use ThinkGeo's WPF NuGet package that will provide us with a map control and a full suite of GIS tools to use.

Open the NuGet Package Manager by right-clicking on your project in the Solution Explorer and select Manage NuGet Packages. Search for ThinkGeo.UI.Wpf and add it to your project.

Or if you prefer, you can install the package using the dotnet CLI:


    dotnet add package ThinkGeo.UI.WPF

Right-click on your project in the Solution Explorer and select Manage NuGet Packages. Search for ThinkGeo.UI.Wpf and add it to your project.

After the installation is complete, you will see several packages installed. The most important of which being:

  • ThinkGeo.UI.WPF - WPF controls for displaying maps, interactive spatial drawing, and more.
  • ThinkGeo.Core - GIS classes and functions for layers, styles, and performing geospatial operations.

NOTE

In order to use ThinkGeo products in your application, you will need to create a ThinkGeo Account and install the license on your development environment.

Follow ThinkGeo's guide to getting started with ThinkGeo Desktop Maps to install a free 30-day trial license.

Add the Map Control

Now that our application is setup, we can start building. We will start with adding a map to the window. In order to use ThinkGeo's map control, we will need to add the ThinkGeo namespace in the Window control in MainWindow.xaml:


xmlns:tg="clr-namespace:ThinkGeo.UI.Wpf;assembly=ThinkGeo.UI.Wpf"

With the namespace added, we can now add the Map control to the Grid:


    <Grid>
        <!-- Map -->
        <tg:MapView x:Name="map" MapUnit="DecimalDegree" Loaded="Map_Loaded"/>
    </Grid>

We will name the Map control to "map" so that we can reference it in the code-behind. We also need to set the map's unit of measurement, usually to whatever measurement the data being displayed is in. In this case, we are using data from Natural Earth, so we will use DecimalDegree as the map unit to match. Finally, a Map_Loaded event handler is added to the map so that we can load the data as soon as the map is ready.

NOTE

GIS data in different units of measurement from the map will have to be reprojected, or converted, from its unit type to the map's unit type in order to be displayed properly. we will cover the nuances of reprojection in a future blog article.

Displaying SQLite Data

With the MapView added to the application's window, we can begin to display the SQLite in the map control.

Create the SQLite Layer

Here as following is what our SQLite data looks like. Our table is named ne_110m_land, which contains a feature id column and a geometry column. This data will be displayed on the map.

SQLiteDB.png

Next in the Map_loaded event we will create a SQLiteFeatureLayer. To create the SQLiteFeatureLayer we need the following parameters: Connection string, Table name, Feature id column, and the geometry column.

Download ne-110m_land.sqlite, create a SqliteFeatureLayer in Map_Loaded method and style it.


    private void Map_Loaded(object sender, RoutedEventArgs e)
    {
        // Here we create SQLite feature layer by passing in the connection string, table name, name of the feature id column, and the name of the geometry column.
        SqliteFeatureLayer sqlitLayer = new SqliteFeatureLayer(@"Data Source=Data\ne_110m_land.sqlite", "ne_110m_land", "id", "geometry");
    
        // Set the default area style and apply it to all 20 ZoomLevels.
        sqlitLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = new AreaStyle(GeoPens.Black);
        sqlitLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
    }

As you can see, styles are added to what is called a ZoomLevelSet. A ZoomLevelSet, by default, contains 20 zoom levels, or geometric scale breakpoints, that allow you to design how your layer looks depending on how zoomed in the user is on the map. You can then assign multiple styles at each ZoomLevel and apply those styles across other scales.

In our case, we are just assigning a simple AreaStyle with a black outline on all 20 zoom levels.

Add the Layer to a LayerOverlay

Now that the layer is styled, we need to add a LayerOverlay that will contain our Sqlite layer. An Overlay is essentially a container that holds a collection of objects. There are several types of overlays that contain things such as map adornments, feature layers, and editable features. In this case, we need a LayerOverlay to contain Layer objects for our Sqlite. We will then add that overlay to the map so that it will be visible.


    private void Map_Loaded(object sender, RoutedEventArgs e)
    {
        // Here we create SQLite feature layer.
        [...]
         
		// Set the default area style and apply it to all 20 ZoomLevels
       	[...]
        
        // Create an Overlay to store the layer and add it to the map.
        LayerOverlay landOverlay = new LayerOverlay();
        map.Overlays.Add(landOverlay);
        landOverlay.Layers.Add(sqlitLayer);
    }

Set the Map's Extent

When the application loads, we want to make sure we can see the SQLite data. In order to do this, we can simply make a query on the sqlitLayer to find the bounding box of all its data. We can then set the Map's view to match that:


    private void Map_Loaded(object sender, RoutedEventArgs e)
    {
        // Here we create SQLite feature layer.
        [...]

		// Set the default area style and apply it to all 20 ZoomLevels
        [...]
    
        // Create an Overlay to store the layer and add it to the map.
        [...]
    
        // Set the map's extent to the bounding box of the sqlitLayer
        sqlitLayer.Open();
        map.CurrentExtent = sqlitLayer.GetBoundingBox();
        map.Refresh();
    }

Run the Application

When you run the application, you will see the SQLite data displayed on the map. Below is how the application looks when I load up Natural Earth's basic land data:

With that, our application is complete. Here is the gitlab repo where you can find the complete source code.

SampleResult.png

Closing Remarks

Thank you for sticking with me through this tutorial. Be sure to check out our other education blog articles for more of what ThinkGeo can do for you. Let us know if there are any subjects that you would like to see covered in future blog articles!

Check out ThinkGeo's Desktop Maps product page for more of what features you'll get from our products!

Previous
Previous

ThinkGeo 10 to 12 Conversion Guide

Next
Next

Display Maps in .NET 5 WPF Using VS Code