Offline searching

In this section, we're going to discuss queries and spatial queries using local content in the Runtime geodatabase.

Querying local layers

Not only can you search online content, but you can also search through an ArcGIS Runtime geodatabase. However, in order to accomplish this, you can't use QueryTask or FindTask because they require a URI to an online data source. Also, you will need to access the local geodatabase's table instead of directly accessing the layer. To get access to the table, we must first open the ArcGIS Runtime geodatabase. Let's look at an example:

var gdb = await Geodatabase.OpenAsync(this.GDB);

Envelope extent = null;
foreach (var table in gdb.FeatureTables)
{
    var flayer = new FeatureLayer()
{
    ID = table.Name,
    DisplayName = "Parking Meters",
    FeatureTable = table
};

You've seen this code before. It simply opens a Runtime geodatabase (SQL Lite), and then creates a FeatureLayer resource. Let's create some code to search for a parking meter:

  1. Create a new ArcGIS Runtime app with MVVM Light and Json.NET, or take a look at the sample that came with this book called Chapter7a.
  2. Add the following XAML code:
    <TextBlock  Name="Search" Background="#77000000" 
        HorizontalAlignment="Center"
        VerticalAlignment="Top" Padding="5" 
        Foreground="White" >
        <Run>Enter a parking meter ID:  </Run>
        <TextBox Name="SearchTextBox" Width="50" Text="{Binding 
            SearchText}"></TextBox>
    
        <Button Content="Find" Width="50" Command="{Binding 
            SearchRelayCommand}" 
            CommandParameter="{Binding Path=Text,  
            ElementName=SearchTextBox}" >
        </Button>
    </TextBlock> 
  3. Add the following private member RelayCommand to the MainViewModel class:
    public RelayCommand<string> SearchRelayCommand { get; private set; }
  4. In the constructor, instantiate the RelayCommand member:
    this.SearchRelayCommand = new RelayCommand<string>(Search);
  5. Create a method that takes in the search text and perform the search:
    public async void Search(string searchString)
    {
        FeatureLayer featureLayer = this.mapView.Map.Layers[1] as 
            FeatureLayer;
        GeodatabaseFeatureTable table = featureLayer.FeatureTable as 
            GeodatabaseFeatureTable;
    
        // Define an attribute query
        var filter = new Esri.ArcGISRuntime.Data.QueryFilter();
        filter.WhereClause = "POST_ID = '" +
        searchString + "'"; // 666-13080
    
        // Execute the query and await results
        IEnumerable<Feature> features = await table.QueryAsync(filter);
    
        foreach(Feature feature in features)
        {
            string address = feature.Attributes["STREETNAME"] as string;
            System.Diagnostics.Debug.WriteLine("Address: " + address);
        }
    
    }
  6. Run the app and enter 666-13080 as the meter ID. The address will be sent to the Visual Studio Output window in this example.

As you can see from this code, the process is still quite similar to using a QueryTask class, except that we had to get the table of FeatureLayer. We then set a QueryFilter object using a WHERE clause. In this particular layer, the meter's ID is called POST_ID. It is of type string. Once the query is finished, it returns an enumerable list of features, which we iterated through to get the address in this case. One significant piece of information to be aware of is that querying the ArcGIS Runtime geodatabase requires that you follow the syntax rules of SQLite. For more information, navigate to http://www.sqlite.org/docs.html.

Spatial querying local layers

Let's do something a little more interesting with offline data in this section. In this section, we're going to search for all the meters within 200 meters of meter 666-13080. To implement this, add a new method to your ViewModel class called SearchByMeterID. It will have the same signature as the previous searching method:

  1. Add the following method:
    public async void SearchByMeterID(string searchString)
    {
        SimpleLineSymbol sls = new SimpleLineSymbol()
        {
            Color = System.Windows.Media.Colors.Red,
            Style = SimpleLineStyle.Solid,
            Width = 2
        };
    
        // get the layer and table
        FeatureLayer featureLayer = this.mapView.Map.Layers[1] as 
            FeatureLayer;
        GeodatabaseFeatureTable table = featureLayer.FeatureTable as 
            GeodatabaseFeatureTable;
    
        // Define an attribute query
        var filter = new Esri.ArcGISRuntime.Data.QueryFilter();
        filter.WhereClause = "POST_ID = '"
            + searchString + "'"; // Try 666-13080
    
        // Execute the query and await results
        IEnumerable<Feature> features = await table.QueryAsync(filter);
    
        // iterate the feature. Should be one in this case.
        foreach (Feature feature in features)
        {
            // Get the MapPoint, Project to Mercator so that we are 
            // working in meters
            MapPoint mapPoint = feature.Geometry as MapPoint;
            MapPoint pointMercator = GeometryEngine.Project(mapPoint, 
                SpatialReferences.WebMercator) as MapPoint;
            Geometry polygon = GeometryEngine.Buffer(pointMercator, 200);
    
            // Re-project the polygon to WGS84 so that we can query   
            // against the layer which is in WGS84
            Polygon polygonWgs84 = GeometryEngine.Project(polygon, 
                SpatialReferences.Wgs84) as Polygon;
    
            // add the circle (buffer)
            Graphic graphic = new Graphic();
            graphic.Symbol = sls;
            graphic.Geometry = polygonWgs84;
            this.graphicsLayer.Graphics.Add(graphic);
    
            // Make sure the table supports querying
            if (table.SupportsQuery)
            {
                // setup the query to use the polygon that's in WGS84
                var query = new SpatialQueryFilter();
                query.Geometry = polygonWgs84 as Geometry;
                query.SpatialRelationship =
                    SpatialRelationship.Intersects;
    
                var result = await table.QueryAsync(query);
    
                // Loop through query results
                foreach (Esri.ArcGISRuntime.Data.Feature f in result)
                {
                    // do something with results
                }
    
            }
        }
    }
  2. Update the RelayCommand and XAML code to find this new method.
  3. Run the app and enter a parking meter ID of 666-13080.

You will see a buffer on the map around the meter found:

Spatial querying local layers

In this method, we've set up a SimpleLineSymbol class so we can view the buffer, retrieved the layer and layer's table, defined a QueryFilter object so that we can get the MapPoint instance of a parking meter, and iterated over the parking meters. Once we have a parking meter, we re-project the parking meter's MapPoint class from WGS84 to Mercator so that we can buffer it using a hardcoded value of 200 meters. We can't use meters with a WGS84 coordinate system because that coordinate system uses angular units. We then compute the buffer, which produces a polygon, and then we re-project the polygon back into WGS84 so that it will display correctly on the map. After that, we create a Graphic class of the buffer and display it on the map. Then, we check to make sure that the table supports being queried. This is an optional setting when the layer was published to a ArcGIS Runtime geodatabase. Then, we set up the SpatialQueryFilter class to use the polygon in WGS84, and set up the spatial relationship to search for any parking meter that intersects with the polygon. Lastly, we issue Query asynchronously, and then iterate over the results.

This example shows how to perform queries on offline data, while at the same time it shows how to perform spatial analysis. Spatial analysis is the primary engine of GIS and we will return to it in a later chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.89.2