Select to view content in your preferred language

Address Location Tool Sample Alternative

3470
11
07-18-2012 02:18 PM
TanyaOwens
Frequent Contributor
Does anyone have or has come across a viewer tool for Address location that follows the structure of the API Address location code from the API concepts http://help.arcgis.com/en/webapi/silverlight/help/index.html#/Address_Locator_task/01660000001r00000... that they would be willing to share? I find the sample address location tool for the viewer difficult to follow and modify.

Thanks!
0 Kudos
11 Replies
TanyaOwens
Frequent Contributor
Below is my attempt at creating the Address Location Tool Alternative. (I am very new to programming) I currently have 3 errors:

1. "The name 'InitializeComponent' does not exist in the current context"
2. "ESRI.ArcGIS.Client.Tasks.Address' does not contain a definition for 'Text'
3. The name 'LayoutRoot' does not exist in the current context"

If someone wouldn't mind taking a look and making suggestions to make this work, I would greatly appreciate it. There is 1 xaml file and 2 cs files:

AddressLocationTool.xaml:
<UserControl x:Class="AddressLocationTool.AddIns.MyConfigDialog"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:esri="http://schemas.esri.com/arcgis/client/2009"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:slData="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
    xmlns:extensibility="clr-namespace:ESRI.ArcGIS.Client.Extensibility;assembly=ESRI.ArcGIS.Client.Extensibility">

    <Grid x:Name="LayoutRoot" Background="White">
       
        <Grid.Resources>
            <esri:PictureMarkerSymbol x:Key="AddressToLocationSymbol" 
                                      OffsetX="0" 
                                      OffsetY="31" 
                                      Source="C:\TOwens\Viewer_Apps\AddressLocationTool\AddressLocationTool\AddressLocationTool\Images\MarkerSymbols\Basic\BlueStickpin.png" />

        </Grid.Resources>



        <!-- LOCATOR TASK INTERFACE -->
        <StackPanel Margin="10" HorizontalAlignment="Left">
            <Grid>
                <Rectangle Fill="#CC5C90B2" 
                           Stroke="Gray"  
                           RadiusX="10" 
                           RadiusY="10" />

                <StackPanel Margin="10" HorizontalAlignment="Center" >
                    <TextBlock Text="Click Find to locate an address" 
                               HorizontalAlignment="Center" 
                               Margin="0,0,0,5" 
                               Foreground="White" 
                               FontStyle="Italic" />

                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
                        <TextBlock Text="Address: " Foreground="White" />
                        <TextBox x:Name="Address" Text="177 N Church Ave" Width="125" />
                    </StackPanel>

                    <Button x:Name="FindAddressButton" 
                            Content="Find" Width="100" 
                            HorizontalAlignment="Center"
                            Click="FindAddressButton_Click" 
                            Margin="0,5,0,0" />
                    <Line HorizontalAlignment="Center" X1="0" Y1="10" X2="180" Y2="10" StrokeThickness="1" Stroke="White" />
                </StackPanel>
            </Grid>
        </StackPanel>


    </Grid>
</UserControl>



AddressLocationTool.xaml.cs:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;
using System.ComponentModel.Composition;
using System.ComponentModel;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Extensibility;
using ESRI.ArcGIS.Client.Tasks;
using ESRI.ArcGIS.Client.Symbols;
using ESRI.ArcGIS.Client.Geometry;
using System.Collections.Generic;

namespace AddressLocationTool.AddIns
{
    public partial class AddressLocationTool : UserControl
    {
        public AddressLocationTool()
        {
            InitializeComponent();
        }


        // Find the location of an address when the Find button is clicked.
        private void FindAddressButton_Click(object sender, RoutedEventArgs e)
        {
            // Initialize the Locator.
            Locator locatorTask = new Locator("GeocodeServer web address" +
              "Locators/ESRI_Geocode_USA/GeocodeServer");
            locatorTask.AddressToLocationsCompleted += LocatorTask_AddressToLocationsCompleted;
            locatorTask.Failed += LocatorTask_Failed;

            // Initialize the address.
            AddressToLocationsParameters addressParameters = new AddressToLocationsParameters();
            Dictionary<string, string> address = addressParameters.Address;

            address.Add("Address", Address.Text);

            // Call method to locate the address.
            locatorTask.AddressToLocationsAsync(addressParameters);
        }

        // When the address has been located, show the best match on the map.
        private void LocatorTask_AddressToLocationsCompleted(object sender, ESRI.ArcGIS.Client.Tasks.AddressToLocationsEventArgs args)
        {
            // Check whether results were found.
            if (args.Results.Count > 0)
            {
                // Get the best match.
                AddressCandidate bestCandidate = args.Results[0];
                foreach (AddressCandidate candidate in args.Results)
                    bestCandidate = (candidate.Score > bestCandidate.Score) ? candidate : bestCandidate;

                // Create a graphic for the match.
                Graphic graphic = new Graphic()
                {
                    Symbol = LayoutRoot.Resources["AddressToLocationSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol,
                    Geometry = bestCandidate.Location
                };

                // Add the address and coordinates to the graphic.
                graphic.Attributes.Add("Address", bestCandidate.Address);
                string latLon = String.Format("{0}, {1}", bestCandidate.Location.X, bestCandidate.Location.Y);
                graphic.Attributes.Add("LatLon", latLon);

                // Show the graphic by adding it to a graphics layer.
                GraphicsLayer graphicsLayer = MapApplication.Current.Map.Layers["AddressToLocationGraphicsLayer"] as GraphicsLayer;
                graphicsLayer.ClearGraphics();
                graphicsLayer.Graphics.Add(graphic);
            }
            else
            {
                // Notify user.
                MessageBox.Show("No results found");
            }
        }

        // Notify the user if the task fails to execute.
        private void LocatorTask_Failed(object sender, TaskFailedEventArgs e)
        {
            MessageBox.Show("Locator service failed: " + e.Error);
        }
    }

}


AddressTool.cs:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;
using System.ComponentModel.Composition;
using System.ComponentModel;
using ESRI.ArcGIS.Client;
using ESRI.ArcGIS.Client.Extensibility;

namespace AddressLocationTool.AddIns
{
    [Export(typeof(ICommand))]
    [DisplayName("Address Location")]
    public class AddressTool : ICommand
    {
        private AddressLocationTool addressUI;
        public AddressTool()
        {
            addressUI = new AddressLocationTool();
        }

        public void Execute(object parameter)
        {

            MapApplication.Current.ShowWindow("Address Location", addressUI);
        }

        public bool CanExecute(object parameter)
        {
            // Return true so that the command can always be executed
            return true;
        }

        public event EventHandler CanExecuteChanged;

        
    }
}


Thanks in advance for any help.
0 Kudos
KatherineDalton
Esri Regular Contributor
Hi Tanya,

I can definitely understand that the Locate Address sample can seem a bit overwhelming. It is one of our larger samples, and designed to show several different programming practices, including the MVVM pattern. That said, it is actually going to be a better starting point for you for Viewer add-ins than using the sample from the ArcGIS API for Silverlight. The implementation is slightly different for the Viewer, and with the sample we created, we took care of most of the little bits you'd have to do yourself.

I believe at the UC you mentioned that you really only need your users to enter a Street address, and that the City/State are always the same? Here are a few suggestions to get you started with the existing Locate Address sample: First, go in to the LocateAddressView.xaml file and comment out the StackPanels that contain the fields you do not need. (I'd recommend just commenting out any lines of code or xaml at this point instead of removing them completely). Then, go to the AddressToLocationCommand.cs file, which is hooked up to fire when the Find button is clicked. In the Execute method, hard-code the values for City and State (this is one option and there are certainly others):

Dictionary<string, string> addressDict = addressParams.Address;
            addressDict.Add("Street", address.Street);
            addressDict.Add("City", "Redlands"); //Hardcoded city
            addressDict.Add("State", "CA"); //Hardcoded state
            addressDict.Add("Zip", address.ZipCode);

In the CanExecute method, which is checking to see that all fields have been filled out, you only need one check for "return !string.IsNullOrEmpty(address.Street);" instead of the existing line that checks the Street, City, State, and Zip:


   //return !string.IsNullOrEmpty(address.Street) && !string.IsNullOrEmpty(address.City)
   //    && !string.IsNullOrEmpty(address.State) && !string.IsNullOrEmpty(address.ZipCode);

    return !string.IsNullOrEmpty(address.Street);

The other code files you see in the project are just there to do things like create the graphic, add the matches/address candidates as graphics, and so forth, so although it seems like a lot, they're doing very specific functions and have minimal code.

Please let me know if you have additional questions on this.

Katy
Katy Dalton | Technical Consultant
THE SCIENCE OF WHERE™
0 Kudos
TanyaOwens
Frequent Contributor
Hi Katy,
Thanks for getting back to me, I really appreciate it. I will give this a shot but the real reason I was trying to use the ArcGIS API for Silverlight sample is so I could hook into the identify task from the API sample. I am very new to programming in general and the MVVM pattern confuses me on how I would add another aspect, such as identify, to the address location tool. There currently is no samples for an identify task for the viewer which adds to the difficulty. My final product needs to be one button click that uses the address point to identify 3 separate layers in my web application and returns the results via pop-up or datagrid. Basically I have the following questions:

1. Is it possible to make the viewer address location sample and the identify tool sample from the API into a single button click tool?

2. If so, do you have any words of advice I can get about combining the address location and identify tools using the MVVM pattern? I am not even sure where to start.

3. Do you have any examples of a combination of two tools using the MVVM pattern?

Thanks again for your help,
-Tanya
0 Kudos
KatherineDalton
Esri Regular Contributor
Hi Tanya,

Are you saying that the default on-click pop-up (Identify functionality) that come with the Viewer is not giving you the information that you need? Or do you want it to automatically show as soon as they click Find on the Address Locator and zoom to the location? One problem I could foresee with that is that often times a list of "candidates" are returned from the Locator Task, in which case it would be tough to decide which spot on the map should automatically show the pop-up.

Katy
Katy Dalton | Technical Consultant
THE SCIENCE OF WHERE™
0 Kudos
TanyaOwens
Frequent Contributor
Hi Tanya,

Are you saying that the default on-click pop-up (Identify functionality) that come with the Viewer is not giving you the information that you need? Or do you want it to automatically show as soon as they click Find on the Address Locator and zoom to the location? One problem I could foresee with that is that often times a list of "candidates" are returned from the Locator Task, in which case it would be tough to decide which spot on the map should automatically show the pop-up.

Katy


Having it to automatically show the the pop-up as soon as they click Find on the Address locator and zoom to that location is exactly what I need. In my API code we used bestCandidate to get past the list of candidates. See code:

        private void LocatorTask_AddressToLocationsCompleted(object sender, ESRI.ArcGIS.Client.Tasks.AddressToLocationsEventArgs args)
        {
            // Check whether results were found.
            if (args.Results.Count > 0)
            {
                // Get the best match.
                AddressCandidate bestCandidate = args.Results[0];
                foreach (AddressCandidate candidate in args.Results)
                    bestCandidate = (candidate.Score > bestCandidate.Score) ? candidate : bestCandidate;

                // Create a graphic for the match.
                Graphic graphic = new Graphic()
                {
                    Symbol = LayoutRoot.Resources["AddressToLocationSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol,
                    Geometry = bestCandidate.Location
                };

                //Zoom to Graphic - Location to Address
                Envelope env = new Envelope(bestCandidate.Location.X - 4000, bestCandidate.Location.Y - 4000, bestCandidate.Location.X + 4000, bestCandidate.Location.Y + 4000);
                MyMap.ZoomTo(env);

                //Identify Parameters for Address to Location Point
                ESRI.ArcGIS.Client.Tasks.IdentifyParameters identifyParams = new IdentifyParameters()
                {
                    //This is where the xy coords are passed into the parameters
                    Geometry = bestCandidate.Location,
                    MapExtent = MyMap.Extent,
                    Width = (int)MyMap.ActualWidth,
                    Height = (int)MyMap.ActualHeight,
                    LayerOption = LayerOption.all,
                    SpatialReference = MyMap.SpatialReference
                };

                identifyParams.LayerIds.AddRange(new int[] { 2, 3, 4 });


                IdentifyTask identifyTask = new IdentifyTask("website");
                identifyTask.ExecuteCompleted += IdentifyTask_ExecuteCompleted;
                identifyTask.Failed += IdentifyTask_Failed;
                identifyTask.ExecuteAsync(identifyParams);

                // Add the address and coordinates to the graphic.
                graphic.Attributes.Add("Address", bestCandidate.Address);
                string latLon = String.Format("{0}, {1}", bestCandidate.Location.X, bestCandidate.Location.Y);
                graphic.Attributes.Add("LatLon", latLon);

                // Show the graphic by adding it to a graphics layer.
                GraphicsLayer graphicsLayer = MyMap.Layers["AddressToLocationGraphicsLayer"] as GraphicsLayer;
                graphicsLayer.ClearGraphics();
                graphicsLayer.Graphics.Add(graphic);
            }
            else
            {
                // Notify user.
                MessageBox.Show("No results found");
            }
        }


Thanks
0 Kudos
KatherineDalton
Esri Regular Contributor
Sorry for the delay, Tanya. Okay, I checked with our lead developer, and what needs to happen is that you need to take the coordinates from your match graphic and use that to find the location in your FeatureLayer/GraphicsLayer and then show the pop-up. The way to do this is to use GraphicsLayer.FindGraphicsInHostCoordinates as shown below. Also note the use of the Transformation to ensure the proper screen coordinates relative to the application.


            
Map map = MapApplication.Current.Map;
MapPoint mapPoint = (MapPoint)matchGraphic.Geometry;
Point screenPoint = map.MapToScreen(mapPoint, true);

GeneralTransform t;
if (Application.Current != null)
{
    if (map.FlowDirection == FlowDirection.RightToLeft)
        t = map.TransformToVisual(null);
    else
        t = map.TransformToVisual(Application.Current.RootVisual);
}
else
    t = map.TransformToVisual(null);

screenPoint = t.Transform(screenPoint);

string layerId = "a0105e7ed35a4618ab0d052611dc0298";
GraphicsLayer graphicsLayer = MapApplication.Current.Map.Layers[layerId] as GraphicsLayer;

IEnumerable<Graphic> graphics = graphicsLayer.FindGraphicsInHostCoordinates(screenPoint);
Graphic graphic = graphics.FirstOrDefault();

MapApplication.Current.ShowPopup(graphic, graphicsLayer);
Katy Dalton | Technical Consultant
THE SCIENCE OF WHERE™
0 Kudos
TanyaOwens
Frequent Contributor
Hi Katy,

Thanks for being patient and helping me.

Sorry like I said, I am very new to programming. Does this needed to be added to Address Location tool sample? And if so, is it a separate .cs file. And if that is so, should it go under Model or View Model. Sorry again. If it isn't a separate .cs file - which one should be modified to add that code.

Also I have another post that I really need the answer to: http://forums.arcgis.com/threads/63897-Pop-up-Hyperlink-alias. Maybe you can help me?

Thanks,

Tanya
0 Kudos
KatherineDalton
Esri Regular Contributor
Hi Tanya,

No problem at all. There are probably a few different options for where to put it, based on how you may have tweaked the original code. I put it in the CandidatesToGraphicsAction.cs file. I've attached that here. 

And I'll take a look at your other forum post today. 🙂

Katy
Katy Dalton | Technical Consultant
THE SCIENCE OF WHERE™
0 Kudos
TanyaOwens
Frequent Contributor
Thanks again,

I added this code directly to the original sample locate address and I get the following error:

"Object reference not set to an instance of an object."

with a long list of details starting with:

at LocateAddress.AddIns.CandidatesToGraphicsAction.Invoke(Object parameter).

Maybe I am missing a step or two?



Thanks,

Tanya
0 Kudos