ArcGISPortalViewer.ViewModel.MapViewModel.Query C# (CSharp) Method

Query() public method

public Query ( string text ) : Task
text string
return Task
        public async Task Query(string text)
        {
            try
            {
                if (Controller == null)
                    return;

                IsLoadingSearchResults = true;
                text = text.Trim();

                if (_searchCancellationTokenSource != null)
                {
                    if (_currentSearchString != null && _currentSearchString == text)
                        return;
                    _searchCancellationTokenSource.Cancel();
                }
                _searchCancellationTokenSource = new CancellationTokenSource();
                var cancellationToken = _searchCancellationTokenSource.Token;
                Envelope boundingBox = Controller.Extent;
                if (string.IsNullOrWhiteSpace(text)) return;
                if (_currentSearchString != null && _currentSearchString != text)
                {
                    if (!cancellationToken.IsCancellationRequested)
                        _searchCancellationTokenSource.Cancel();
                }
                _searchResultLayer.Graphics.Clear();
                var geo = new OnlineLocatorTask(new Uri("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer", UriKind.Absolute), "");

                boundingBox = boundingBox.Expand(1.2);
               
                _currentSearchString = text;
                SearchResultStatus = string.Format("Searching for '{0}'...", text.Trim());
                var result = await geo.FindAsync(new OnlineLocatorFindParameters(text)
                {
                    MaxLocations = 25,                    
                    OutSpatialReference = WebMapVM.SpatialReference,
                    SearchExtent = boundingBox,
                    Location = (MapPoint)GeometryEngine.NormalizeCentralMeridian(boundingBox.GetCenter()),
                    Distance = GetDistance(boundingBox),
                    OutFields = new List<string>() { "PlaceName", "Type", "City", "Country" }                    
                }, cancellationToken);

                // if no results, try again with larger and larger extent
                var retries = 3;
                while (result.Count == 0 && --retries > 0)
                {
                    if (cancellationToken.IsCancellationRequested)
                        return;
                    boundingBox = boundingBox.Expand(2);
                    result = await geo.FindAsync(new OnlineLocatorFindParameters(text)
                    {
                        MaxLocations = 25,
                        OutSpatialReference = WebMapVM.SpatialReference,
                        SearchExtent = boundingBox,
                        Location = (MapPoint)GeometryEngine.NormalizeCentralMeridian(boundingBox.GetCenter()),
                        Distance = GetDistance(boundingBox),
                        OutFields = new List<string>() { "PlaceName", "Type", "City", "Country"}
                    }, cancellationToken);
                }
                if (cancellationToken.IsCancellationRequested)
                    return;

                if (result.Count == 0) 
                {
                    // atfer trying to expand the bounding box several times and finding no results, 
                    // let us try finding results without the spatial bound.
                    result = await geo.FindAsync(new OnlineLocatorFindParameters(text)
                    {
                        MaxLocations = 25,
                        OutSpatialReference = WebMapVM.SpatialReference,
                        OutFields = new List<string>() { "PlaceName", "Type", "City", "Country"}
                    }, cancellationToken);

                    if (result.Any())
                    {
                        // since the results are not bound by any spatial filter, let us show well known administrative 
                        // places e.g. countries and cities, and filter out other results e.g. restaurents and business names.
                        var typesToInclude = new List<string>()
                        { "", "city", "community", "continent", "country", "county", "district", "locality", "municipality", "national capital", 
                          "neighborhood", "other populated place", "state capital", "state or province", "territory", "village"};
                        for (var i = result.Count - 1; i >= 0; --i)
                        {
                            // get the result type
                            var resultType = ((string)result[i].Feature.Attributes["Type"]).Trim().ToLower();
                            // if the result type exists in the inclusion list above, keep it in the list of results
                            if (typesToInclude.Contains(resultType))
                                continue;
                            // otherwise, remove it from the list of results
                            result.RemoveAt(i);
                        }
                    }
                }

                if (result.Count == 0)
                {
                    SearchResultStatus = string.Format("No results for '{0}' found", text);
                    if (Locations != null)
                        Locations.Clear();
                    //await new Windows.UI.Popups.MessageDialog(string.Format("No results for '{0}' found", text)).ShowAsync();
                }
                else
                {
                    SearchResultStatus = string.Format("Found {0} results for '{1}'", result.Count.ToString(), text);
                    Envelope extent = null;
                    var color = (App.Current.Resources["AppAccentBrush"] as SolidColorBrush).Color;
                    var color2 = (App.Current.Resources["AppAccentForegroundBrush"] as SolidColorBrush).Color;
                    SimpleMarkerSymbol symbol = new SimpleMarkerSymbol()
                    {
                        Color = Colors.Black,
                        Outline = new SimpleLineSymbol() { Color = Colors.Black, Width = 2 },
                        Size = 16,
                        Style = SimpleMarkerStyle.Square
                    };

                    // set the picture marker symbol used in the search result composite symbol.
                    var imageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/Icons/SearchResult.png"));
                    var imageSource = await imageFile.OpenReadAsync();
                    var pictureMarkerSymbol = new PictureMarkerSymbol();
                    await pictureMarkerSymbol.SetSourceAsync(imageSource);
                    // apply an x and y offsets so that the tip of of the pin points to the correct location.
                    pictureMarkerSymbol.XOffset = SearchResultPinXOffset;
                    pictureMarkerSymbol.YOffset = SearchResultPinYOffset;

                    int ID = 1;
                    foreach (var r in result)
                    {
                        if (extent == null)
                            extent = r.Extent;
                        else if (r.Extent != null)
                            extent = extent.Union(r.Extent);

                        var textSymbol = new TextSymbol()
                        {
                            Text = ID.ToString(),
                            Font = new SymbolFont() { FontFamily = "Verdena", FontSize = 10, FontWeight = SymbolFontWeight.Bold },
                            Color = color2,
                            BorderLineColor = color2,
                            HorizontalTextAlignment = Esri.ArcGISRuntime.Symbology.HorizontalTextAlignment.Center,
                            VerticalTextAlignment = Esri.ArcGISRuntime.Symbology.VerticalTextAlignment.Bottom,
                            XOffset = SearchResultPinXOffset,
                            YOffset = SearchResultPinYOffset
                        }; //Looks like Top and Bottom are switched - potential CR                      

                        // a compsite symbol for both the PictureMarkerSymbol and the TextSymbol could be used, but we 
                        // wanted to higlight the pin without the text; therefore, we will add them separately.

                        // add the PictureMarkerSymbol to _searchResultLayer
                        Graphic pin = new Graphic()
                        {
                            Geometry = r.Extent.GetCenter(),
                            Symbol = pictureMarkerSymbol,
                        };
                        pin.Attributes["ID"] = ID;
                        pin.Attributes["Name"] = r.Name;
                        _searchResultLayer.Graphics.Add(pin);

                        // add the text to _searchResultLayer
                        Graphic pinText = new Graphic()
                        {
                            Geometry = r.Extent.GetCenter(),
                            Symbol = textSymbol,
                        };
                        pinText.Attributes["ID"] = ID;
                        pinText.Attributes["Name"] = r.Name;
                        _searchResultLayer.Graphics.Add(pinText);

                        ID++;
                    }

                    SetResult(result);
                    base.RaisePropertyChanged("IsClearGraphicsVisible");
                    if (extent != null)
                    {
                        var _ = SetViewAsync(extent, 50);
                    }
                }
            }
            finally
            {
                IsLoadingSearchResults = false;
                _searchCancellationTokenSource = null;
                _currentSearchString = null;
            }
        }