Exemple #1
0
        /// <summary>
        /// Execute command.
        /// </summary>
        /// <param name="args">Command args.</param>
        protected override void _Execute(params object[] args)
        {
            System.Windows.Point             point    = (System.Windows.Point)args[0];
            ESRI.ArcLogistics.Geometry.Point location =
                new ESRI.ArcLogistics.Geometry.Point(point.X, point.Y);

            IGeocodable geocodable = (IGeocodable)args[1];

            // Save new GeoLocation anyway.
            geocodable.GeoLocation = new ESRI.ArcLogistics.Geometry.Point(point.X, point.Y);

            // If one or more address fields is not empty - do not fill them with new values
            // otherwise make reversegeocoding request and fill address fields.
            if (CommonHelpers.IsAllAddressFieldsEmpty(geocodable.Address))
            {
                args[IS_RESPONSE_RECEIVED_INDEX] = _ProcessReverseGeocode(geocodable, location);
            }
            else
            {
                args[IS_RESPONSE_RECEIVED_INDEX] = true;
                // In case of manually filled address fields after setting position.
                // set locator to manually edited xy
                string manuallyEditedXY = (string)System.Windows.Application.Current.FindResource(MANUALLY_EDITED_XY_RESOURCE_NAME);
                if (geocodable.Address.MatchMethod == null ||
                    !geocodable.Address.MatchMethod.Equals(manuallyEditedXY, StringComparison.OrdinalIgnoreCase))
                {
                    geocodable.Address.MatchMethod = manuallyEditedXY;
                }
            }

            // Workaround - see method comment.
            CommonHelpers.FillAddressWithSameValues(geocodable.Address);
        }
        /// <summary>
        /// Does objects reverse geocoding.
        /// </summary>
        /// <param name="objects">Objects to geocoding.</param>
        private void _ReverseGeocode(IList <AppData.DataObject> objects)
        {
            Debug.Assert(null != objects);   // created
            Debug.Assert(0 < objects.Count); // not empty
            Debug.Assert(null != _checker);  // inited

            AppGeometry.Envelope extent = App.Current.Map.ImportCheckExtent;

            int count = objects.Count;

            for (int index = 0; index < count; ++index)
            {
                _checker.ThrowIfCancellationRequested();

                if (null == _detectedException)
                {   // NOTE: do if geocoder in valid state
                    IGeocodable geocodable = _GetGeocodable(objects[index]);
                    if (geocodable.GeoLocation.HasValue)
                    {
                        if (extent.IsPointIn(geocodable.GeoLocation.Value))
                        {   // reverse geocode
                            Address geocodedAddress =
                                _ReverseGeocodeSave(geocodable.GeoLocation.Value);
                            if (null != geocodedAddress)
                            {
                                geocodedAddress.CopyTo(geocodable.Address);
                                ++_geocodedCount;
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Pan object geometry.
        /// </summary>
        /// <param name="editingObject">Editing object.</param>
        /// <param name="dx">Pan dx.</param>
        /// <param name="dy">Pan dy.</param>
        private void _PanObject(object editingObject, double dx, double dy)
        {
            Debug.Assert(editingObject != null);
            Debug.Assert(_markersLayer != null);

            IList <EditingMarker> list = (IList <EditingMarker>)_markersLayer.Collection;

            if (editingObject is IGeocodable)
            {
                IGeocodable geocodable = (IGeocodable)editingObject;

                if (geocodable.GeoLocation.HasValue)
                {
                    geocodable.GeoLocation = new Point(geocodable.GeoLocation.Value.X + dx, geocodable.GeoLocation.Value.Y + dy);
                    string manuallyEditedXY = (string)System.Windows.Application.Current.FindResource(MANUALLY_EDITED_XY_RESOURCE_NAME);
                    if (geocodable.Address.MatchMethod == null ||
                        !geocodable.Address.MatchMethod.Equals(manuallyEditedXY, StringComparison.OrdinalIgnoreCase))
                    {
                        geocodable.Address.MatchMethod = manuallyEditedXY;
                    }
                }
            }
            else if (editingObject is Zone)
            {
                Zone zone = (Zone)editingObject;
                zone.Geometry = _PanGeometry(zone.Geometry, dx, dy);
            }
            else if (editingObject is Barrier)
            {
                Barrier barrier = (Barrier)editingObject;
                barrier.Geometry = _PanGeometry(barrier.Geometry, dx, dy);
            }
        }
Exemple #4
0
        /// <summary>
        /// Make string like 'Bevmo could not be found in Redlands,CA.'
        /// </summary>
        /// <param name="item">Geocodable item.</param>
        /// <returns>Geocode result string.</returns>
        private string _MakeNotFoundString(IGeocodable item)
        {
            string resultFmt = (string)App.Current.FindResource(GEOCODE_RESULT_RESOURCE_NAME);

            string cityStateString = string.Empty;

            // Use both fields if both not empty. Use not empty otherwise.
            if (!string.IsNullOrEmpty(item.Address.Locality3) && !string.IsNullOrEmpty(item.Address.StateProvince))
            {
                cityStateString = string.Format(CITY_STATE_FMT, item.Address.Locality3, item.Address.StateProvince);
            }
            else if (!string.IsNullOrEmpty(item.Address.Locality3))
            {
                cityStateString = item.Address.Locality3;
            }
            else if (!string.IsNullOrEmpty(item.Address.StateProvince))
            {
                cityStateString = item.Address.StateProvince;
            }

            string inString = string.Empty;

            // If city or state present - make "in" string.
            if (!string.IsNullOrEmpty(cityStateString))
            {
                inString = string.Format((string)App.Current.FindResource(IN_ADDRESS_RESOURCE_NAME), cityStateString);
            }

            string result = string.Format(resultFmt, item.ToString(), inString);

            return(result);
        }
        /// <summary>
        /// Parses batch geocoding result. Set geocode candidates values to relative object.
        /// </summary>
        /// <param name="candidates">Candidates from geocoding.</param>
        /// <param name="objects">Objects to geocoding.</param>
        private void _ParseBatchGeocodeResult(AddressCandidate[] candidates,
                                              IList <AppData.DataObject> objects)
        {
            Debug.Assert(null != objects);                    // created
            Debug.Assert(null != candidates);                 // created
            Debug.Assert(candidates.Length == objects.Count); // valid state
            Debug.Assert(null != _checker);                   // inited

            // valid check extent
            var importExtent = App.Current.Map.ImportCheckExtent;

            // init progress
            int count = objects.Count;

            for (int index = 0; index < count; ++index)
            {
                _checker.ThrowIfCancellationRequested();

                // get current object
                AppData.DataObject obj        = objects[index];
                IGeocodable        geocodable = _GetGeocodable(obj);

                bool needMessage = false;
                if (geocodable.IsGeocoded)
                {   // add message - Could not locate object using X/Y attributes.
                    // Order was located using address information instead
                    Debug.Assert(!importExtent.IsPointIn(geocodable.GeoLocation.Value));
                    needMessage = true;
                }

                AddressCandidate candidate = candidates[index];
                _UpdateGeocodableInfo(needMessage, candidate, obj);
            }
        }
        /// <summary>
        /// Updates geocodable information.
        /// </summary>
        /// <param name="needMessage">Need show message.</param>
        /// <param name="candidate">Geocoded candidate (can be NULL).</param>
        /// <param name="obj">Source object to geocoded candidate.</param>
        private void _UpdateGeocodableInfo(bool needMessage,
                                           AddressCandidate candidate,
                                           AppData.DataObject obj)
        {
            Debug.Assert(null != obj); // Created.

            IGeocodable geocodable = _GetGeocodable(obj);

            geocodable.GeoLocation = null;

            if ((null == candidate) || (candidate.Score <= App.Current.Geocoder.MinimumMatchScore))
            {
                // Not geocoded.
                geocodable.Address.MatchMethod = string.Empty;
            }
            else
            {
                GeocodeHelpers.SetCandidate(geocodable, candidate);
                ++_geocodedCount;

                // Store warning.
                if (needMessage)
                {
                    string objectName      = _informer.ObjectName;
                    string errorTextFormat =
                        App.Current.GetString("ImportProcessStatusRecordOutMapExtendGeocodedFormat",
                                              objectName.ToLower(),
                                              "{0}",
                                              objectName);
                    var description =
                        new MessageDetail(MessageType.Warning, errorTextFormat, obj);
                    _details.Add(description);
                }
            }
        }
Exemple #7
0
        /// <summary>
        /// Make reverse geocode request and fill geocodable object with new address fields values.
        /// </summary>
        /// <param name="geocodable">Geocodable to fill.</param>
        /// <param name="location">Geolocation point for request.</param>
        /// <returns>Is responce was received.</returns>
        private bool _ProcessReverseGeocode(IGeocodable geocodable, ESRI.ArcLogistics.Geometry.Point location)
        {
            bool result = false;

            try
            {
                Address geocodedAddress = App.Current.Geocoder.ReverseGeocode(location);

                // In case of not empty response - fill address.
                if (geocodedAddress != null)
                {
                    geocodedAddress.CopyTo(geocodable.Address);
                }
                else
                {
                    geocodable.Address.MatchMethod = (string)App.Current.FindResource(MANUALLY_EDITED_XY_FAR_FROM_NEAREST_ROAD_RESOURCE_NAME);
                }

                result = true;
            }
            catch (Exception ex)
            {
                if (ex is AuthenticationException || ex is CommunicationException)
                {
                    string service = (string)App.Current.FindResource(GEOCODING_SERVICE_NAME_RESOURCE_NAME);
                    CommonHelpers.AddServiceMessage(service, ex);
                }
                else
                {
                    throw;
                }
            }

            return(result);
        }
 /// <summary>
 /// Geocode order
 /// </summary>
 private void _Geocode()
 {
     if (OptimizePage.SelectedItems.Count == 1)
     {
         IGeocodable order = (IGeocodable)OptimizePage.SelectedItems[0];
         OptimizePage.StartGeocoding(order);
     }
 }
 /// <summary>
 /// Geocode locations
 /// </summary>
 protected override void _Geocode()
 {
     if (((ISupportSelection)ParentPage).SelectedItems.Count == 1)
     {
         IGeocodable location = (IGeocodable)((ISupportSelection)ParentPage).SelectedItems[0];
         ((LocationsPage)ParentPage).StartGeocoding(location);
     }
 }
        /// <summary>
        /// Check is location of geocodable object valid and replace it by candidate from local
        /// geocoder if exists.
        /// </summary>
        /// <param name="geocodable">Geocodable object to check.</param>
        /// <returns>Is geocodable object valid.</returns>
        private bool _SourceGeocodedObject(IGeocodable geocodable)
        {
            Debug.Assert(null != geocodable); // created

            bool isObjectGeocoded = false;

            // First check if name address pair exists in local geocoder database.
            // If exists - overwrite geolocation and address from it.
            App currentApp    = App.Current;
            var localGeocoder =
                new LocalGeocoder(currentApp.Geocoder, currentApp.NameAddressStorage);

            var nameAddress = new NameAddress();

            nameAddress.Name    = geocodable.ToString();
            nameAddress.Address = geocodable.Address.Clone() as Address;

            AddressCandidate localCandidate = localGeocoder.Geocode(nameAddress);

            if (localCandidate == null)
            {   // Update from internal object information.
                AppGeometry.Envelope extent = currentApp.Map.ImportCheckExtent;
                if (extent.IsPointIn(geocodable.GeoLocation.Value))
                {
                    geocodable.Address.MatchMethod =
                        currentApp.FindString("ImportSourceMatchMethod");
                    isObjectGeocoded = true;

                    // Full address property must be combined from other fields, because
                    // it is not importing field.
                    if (App.Current.Geocoder.AddressFormat == AddressFormat.MultipleFields)
                    {
                        GeocodeHelpers.SetFullAddress(geocodable.Address);
                    }
                    else
                    {
                        // Do nothing: do not update full address since
                        // it is used for geocoding in Single Address Field Format.
                    }
                }
                // Else could not locate object using X/Y attributes - need geocode.
            }
            else
            {   // Init from local candidate.
                // Set location.
                geocodable.GeoLocation = new AppGeometry.Point(localCandidate.GeoLocation.X,
                                                               localCandidate.GeoLocation.Y);
                // Set address.
                localCandidate.Address.CopyTo(geocodable.Address);

                isObjectGeocoded = true;
            }

            return(isObjectGeocoded);
        }
Exemple #11
0
        /// <summary>
        /// Get geocode result for subpage.
        /// </summary>
        /// <param name="item">Geocoded item.</param>
        /// <param name="context">Ignored.</param>
        /// <returns>Current geocode process result.</returns>
        public string GetGeocodeResultString(IGeocodable item, object context)
        {
            if (item == null)
            {
                return(string.Empty);
            }

            string resultFmt = (string)App.Current.FindResource(GEOCODE_RESULT_RESOURCE_NAME);
            string result    = string.Format(resultFmt, item.ToString());

            return(result);
        }
Exemple #12
0
        /// <summary>
        /// Get current geocodable object.
        /// </summary>
        /// <param name="mapctrl">Map control.</param>
        /// <returns>Current geocodable object.</returns>
        private IGeocodable _GetCurrentGeocodableObject(MapControl mapctrl)
        {
            // Current geocodable object is edited object or,
            // in case of address by point tool activated, selected object.
            IGeocodable result = mapctrl.EditedObject as IGeocodable;

            if (result == null && mapctrl.CurrentTool is AddressByPointTool)
            {
                Debug.Assert(mapctrl.SelectedItems.Count == 1);
                result = mapctrl.SelectedItems[0] as IGeocodable;
            }

            return(result);
        }
        /// <summary>
        /// Get street candidate. Extract street name, check that part of street name wasn't removed and try to geocode.
        /// </summary>
        /// <param name="geocodable">Geocodable object to geocode,</param>
        /// <param name="streetLocators">Street locators.</param>
        /// <param name="candidatesIncludedDisabledLocators">Geocoded candidates.</param>
        /// <returns>Street candidate.</returns>
        private static List <AddressCandidate> _GetStreetCandidates(
            IGeocodable geocodable,
            IEnumerable <LocatorInfo> streetLocators,
            IEnumerable <AddressCandidate> candidatesIncludedDisabledLocators)
        {
            Debug.Assert(geocodable != null);
            Debug.Assert(streetLocators != null);
            Debug.Assert(candidatesIncludedDisabledLocators != null);

            List <AddressCandidate> streetCandidates = null;


            if (!string.IsNullOrEmpty(geocodable.Address.AddressLine))
            {
                string street = _ExtractStreet(geocodable.Address.AddressLine);
                if (!street.Equals(geocodable.Address.AddressLine, StringComparison.OrdinalIgnoreCase))
                {
                    // If number removed from street address check that number wasn't part of street name. For example "8th ave".
                    ICloneable  cloneableItem = geocodable as ICloneable;
                    IGeocodable geocodableWithoutHouseNumber = (IGeocodable)cloneableItem.Clone();

                    geocodableWithoutHouseNumber.Address.AddressLine = street;

                    // Get candidates for address with removed number.
                    List <AddressCandidate> candidatesForRemovedHouseNumber       = DoGeocode(geocodableWithoutHouseNumber, true, false);
                    List <AddressCandidate> streetCandidatesForRemovedHouseNumber = _GetCandidatesFromLocators(streetLocators, candidatesForRemovedHouseNumber);

                    // If best candidate from street locator exists - use it.
                    if (streetCandidatesForRemovedHouseNumber.Count > 0)
                    {
                        streetCandidates = streetCandidatesForRemovedHouseNumber;
                    }
                }
            }

            // If street candidate not set yet - find best candidate from already geocoded candidates.
            if (streetCandidates == null)
            {
                streetCandidates = _GetCandidatesFromLocators(streetLocators, candidatesIncludedDisabledLocators);
            }

            // Fill address fields of street candidate.
            foreach (AddressCandidate candidate in streetCandidates)
            {
                ParseAndFillAddress(candidate.Address);
            }

            return(streetCandidates);
        }
        /// <summary>
        /// Is locator address fields empty.
        /// </summary>
        /// <param name="geocodable">Geocodable object.</param>
        /// <returns>Is locator address fields empty.</returns>
        public static bool IsActiveAddressFieldsEmpty(IGeocodable geocodable)
        {
            bool isEmpty = true;

            foreach (AddressField addressField in App.Current.Geocoder.AddressFields)
            {
                if (!string.IsNullOrEmpty(geocodable.Address[addressField.Type]))
                {
                    isEmpty = false;
                    break;
                }
            }

            return(isEmpty);
        }
 /// <summary>
 /// Show hint "Could not located, but zoomed..."
 /// </summary>
 /// <param name="geocodableItem">Geocodable object.</param>
 /// <param name="candidatesToZoom">Address to which map was zoomed. Null if not zoomed.</param>
 public void ShowZoomToCandidatePopup(IGeocodable geocodableItem, AddressCandidate[] candidatesToZoom)
 {
     if (_isGeocodingHintInitialized)
     {
         // Show hint suspendedly because final selection changed event in datagrid control is suspended.
         // And so hint will be hided on selection changed.
         Dispatcher.BeginInvoke(new Action(delegate()
         {
             if (SelectedItems.Count > 0 && SelectedItems[0] == geocodableItem)
             {
                 GeocodingHint.ShowHint(geocodableItem, candidatesToZoom);
             }
         }), DispatcherPriority.Background);
     }
 }
Exemple #16
0
        /// <summary>
        /// Populate update object warning.
        /// </summary>
        /// <param name="obj">Updated object.</param>
        private void _AddUpdateObjectWarning(AppData.DataObject obj)
        {
            Debug.Assert(null != obj); // created

            IGeocodable geocodable = obj as IGeocodable;

            if (null != geocodable)
            {   // NOTE: workaround - see method comment
                CommonHelpers.FillAddressWithSameValues(geocodable.Address);
            }

            string statusText = App.Current.FindString("ImportProcessStatusUpdated");
            string textFormat = _objectsName + FORMAT_UPDATE_MESSAGE_PART + statusText;

            _details.Add(new MessageDetail(MessageType.Warning, textFormat, obj));
        }
        /// <summary>
        /// Does source geocoding.
        /// </summary>
        /// <param name="objects">Objects to geocoding.</param>
        private void _SourceGeocode(IList <AppData.DataObject> objects)
        {
            Debug.Assert(null != objects);   // created
            Debug.Assert(0 < objects.Count); // not empty
            Debug.Assert(null != _checker);  // inited

            // init progress
            int count = objects.Count;

            // geocode process
            var ungeocoded = new List <AppData.DataObject>();

            for (int index = 0; index < count; ++index)
            {
                _checker.ThrowIfCancellationRequested();

                AppData.DataObject obj        = objects[index];
                IGeocodable        geocodable = _GetGeocodable(obj);

                bool isObjectGeocoded = false;
                if (geocodable.IsGeocoded)
                {
                    // check is geocodable object valid and set candidate
                    // from local geocoder if exists
                    isObjectGeocoded = _SourceGeocodedObject(geocodable);
                    if (isObjectGeocoded)
                    {
                        ++_geocodedCount;
                    }
                }

                if (!isObjectGeocoded)
                {
                    ungeocoded.Add(obj);
                }
            }

            _checker.ThrowIfCancellationRequested();

            // geocode all ungeocoded object by batch geocode
            if (0 < ungeocoded.Count)
            {
                _BatchGeocode(ungeocoded);
            }
        }
        /// <summary>
        /// Does empty geocoding.
        /// </summary>
        /// <param name="objects">Objects to geocoding.</param>
        private void _EmptyGeocode(IList <AppData.DataObject> objects)
        {
            Debug.Assert(null != objects);   // created
            Debug.Assert(0 < objects.Count); // not empty
            Debug.Assert(null != _checker);  // inited

            int count = objects.Count;

            for (int index = 0; index < objects.Count; ++index)
            {
                _checker.ThrowIfCancellationRequested();

                IGeocodable geocodable = _GetGeocodable(objects[index]);
                geocodable.GeoLocation = null;
                Debug.Assert(null != geocodable.Address); // created
                geocodable.Address.MatchMethod = string.Empty;
            }
        }
        /// <summary>
        /// Method gets location point of Depot.
        /// </summary>
        /// <param name="loc">Depot to get information from.</param>
        /// <returns>Point location.</returns>
        /// <exception cref="RouteException">If location is not geocoded.</exception>
        private static Point _GetDepotPoint(Location loc)
        {
            Debug.Assert(loc != null);

            IGeocodable gc = loc as IGeocodable;

            Debug.Assert(gc != null);

            if (!gc.IsGeocoded)
            {
                throw new RouteException(String.Format(
                                             Properties.Messages.Error_LocationIsUngeocoded, loc.Id));
            }

            Debug.Assert(gc.GeoLocation != null);

            return((Point)gc.GeoLocation);
        }
        /// <summary>
        /// React on mouse up.
        /// </summary>
        /// <param name="modifierKeys">Modifier keys state.</param>
        /// <param name="x">X coord.</param>
        /// <param name="y">Y coord.</param>
        public void OnMouseUp(MouseButton pressedButton,
                              ModifierKeys modifierKeys, double x, double y)
        {
            Debug.Assert(_mapControl != null);

            _EndPan();

            if (_editingInProcess)
            {
                App.Current.Project.Save();

                // Save to local geocoder database.
                Order order = _mapControl.EditedObject as Order;
                if (order != null)
                {
                    NameAddressRecord nameAddressRecord = CommonHelpers.CreateNameAddressPair(order, null);

                    // Do save in local storage.
                    App.Current.NameAddressStorage.InsertOrUpdate(nameAddressRecord,
                                                                  App.Current.Geocoder.AddressFormat);
                }

                // Check new position is near to road. Set match method if not.
                IGeocodable geocodable = _mapControl.EditedObject as IGeocodable;
                if (geocodable != null)
                {
                    Address addressUnderPoint = _ReverseGeocode(geocodable.GeoLocation.Value);
                    if (addressUnderPoint == null)
                    {
                        geocodable.Address.MatchMethod = (string)App.Current.FindResource(MANUALLY_EDITED_XY_FAR_FROM_NEAREST_ROAD_RESOURCE_NAME);
                    }
                }

                if (OnComplete != null)
                {
                    OnComplete(this, EventArgs.Empty);
                }
                _editingInProcess = false;
                _editedGraphic    = null;
            }
        }
        /// <summary>
        /// Creates address list for input objects.
        /// </summary>
        /// <param name="objects">Source object.</param>
        /// <returns>Created address list for input objects.</returns>
        /// <remarks>Progress show.</remarks>
        private Address[] _CreateAddressList(IList <AppData.DataObject> objects)
        {
            Debug.Assert(null != objects);   // created
            Debug.Assert(0 < objects.Count); // not empty
            Debug.Assert(null != _checker);  // inited

            // init progress
            int count     = objects.Count;
            var addresses = new Address[count];

            for (int index = 0; index < count; ++index)
            {
                _checker.ThrowIfCancellationRequested();

                IGeocodable geocodable = _GetGeocodable(objects[index]);

                addresses[index] = geocodable.Address;
            }

            return(addresses);
        }
        /// <summary>
        /// Make string parts like 'We couldn’t find… so we’ve zoomed to…'
        /// If street candidate - use Address Line from geocodable item, otherwise(citystate or zip) use full address.
        /// </summary>
        /// <param name="item">Geocodable item.</param>
        /// <param name="candidateToZoom">First candidate to zoom.</param>
        /// <returns>Geocode result string parts.</returns>
        public static string GetZoomedAddress(IGeocodable item, AddressCandidate candidateToZoom)
        {
            LocatorType?locatorType = GeocodeHelpers.GetLocatorTypeOfCandidate(candidateToZoom);

            string zoomedAddress;

            // If locator type of candidate is street than get Address Line.
            if (locatorType.HasValue && locatorType.Value == LocatorType.Street &&
                !string.IsNullOrEmpty(item.Address.AddressLine))
            {
                // Extract street name.
                zoomedAddress = GeocodeHelpers.ExtractStreet(item.Address.AddressLine);
            }
            else
            {
                // Otherwise use full address.
                zoomedAddress = candidateToZoom.Address.FullAddress;
            }

            return(zoomedAddress);
        }
Exemple #23
0
        /// <summary>
        /// Get geocode result for subpage.
        /// </summary>
        /// <param name="item">Geocoded item.</param>
        /// <param name="context">Candidates to zoom.</param>
        /// <returns>Current geocode process result.</returns>
        public string GetGeocodeResultString(IGeocodable item, object context)
        {
            if (item == null)
            {
                return(string.Empty);
            }

            AddressCandidate[] candidatesToZoom = context as AddressCandidate[];

            string result;

            if (candidatesToZoom == null || candidatesToZoom.Length == 0)
            {
                result = _MakeNotFoundString(item);
            }
            else
            {
                result = _MakeNotFoundButZoomedString(item, candidatesToZoom[0]);
            }

            return(result);
        }
        /// <summary>
        /// Show hint.
        /// </summary>
        /// <param name="geocodableItem">Geocodable item.</param>
        /// <param name="candidatesToZoom">Candidates to zoom.</param>
        public void ShowHint(IGeocodable geocodableItem, AddressCandidate[] candidatesToZoom)
        {
            _candidatesToZoom = candidatesToZoom;

            string titleFmt = (string)App.Current.FindResource(GEOCODE_RESULT_NOT_ZOOMED_RESOURCE_NAME);

            TitleText.Text = string.Format(titleFmt, geocodableItem.ToString());

            if (candidatesToZoom == null || candidatesToZoom.Length == 0)
            {
                // If we cant zoom to candidtes - hide corresponding rextblocks.
                ZoomedToText.Visibility      = Visibility.Collapsed;
                ZoomedAddress.Visibility     = Visibility.Collapsed;
                ZoomedAddressType.Visibility = Visibility.Collapsed;
            }
            else
            {
                string zoomedAddress = GeocodeHelpers.GetZoomedAddress(geocodableItem, candidatesToZoom[0]);

                _InitZoomedAddressTypeText(candidatesToZoom[0]);

                // Show "Zoomed to..." text.
                ZoomedAddress.Text       = zoomedAddress;
                ZoomedAddress.Visibility = Visibility.Visible;
                ZoomedToText.Visibility  = Visibility.Visible;
            }

            Visibility = Visibility.Visible;

            UpdateLayout();

            Vector toolsPanelOffset = VisualTreeHelper.GetOffset(_mapControl.toolPanel);

            // Set top of hint under title, tools.
            Canvas.SetTop(this, _mapControl.toolPanel.Margin.Top + toolsPanelOffset.Y +
                          _mapControl.toolPanel.ActualHeight);
            Canvas.SetLeft(this, _mapControl.ActualWidth - this.ActualWidth - _mapControl.toolPanel.Margin.Right);
        }
        /// <summary>
        /// Do geocode of geocodable object.
        /// </summary>
        /// <param name="geocodable">Item to geocode.</param>
        /// <param name="useLocalAsPrimary">Is item just created.</param>
        /// <param name="includeDisabledLocators">Is need to add candidates from disabled locators.</param>
        /// <returns>Candidates list.</returns>
        public static List <AddressCandidate> DoGeocode(IGeocodable geocodable, bool useLocalAsPrimary, bool includeDisabledLocators)
        {
            List <AddressCandidate> candidates = null;

            App.Current.MainWindow.Cursor = Cursors.Wait;

            try
            {
                Order    order    = geocodable as Order;
                Location location = geocodable as Location;
                if (order != null)
                {
                    candidates = _DoLocalOrderGeocode(order, useLocalAsPrimary, includeDisabledLocators);
                }
                else if (location != null)
                {
                    candidates = _DoGeocodeLocation(location, includeDisabledLocators);
                }
            }
            catch (Exception ex)
            {
                if (MustThrowException(ex))
                {
                    throw;
                }
            }
            finally
            {
                App.Current.MainWindow.Cursor = Cursors.Arrow;
            }

            if (candidates == null)
            {
                candidates = new List <AddressCandidate>();
            }

            return(candidates);
        }
Exemple #26
0
        /// <summary>
        /// Make string like 'Bevmo couldn’t be located, we’ve zoomed to Pat’s Ranch Rd.  Use the pushpin tool to locate exactly.'
        /// If street candidate - use Address Line from geocodable item, otherwise(citystate or zip) use full address.
        /// </summary>
        /// <param name="item">Geocodable item.</param>
        /// <param name="candidateToZoom">First candidate to zoom.</param>
        /// <returns>Geocode result string.</returns>
        private string _MakeNotFoundButZoomedString(IGeocodable item, AddressCandidate candidateToZoom)
        {
            string messageFmt = (string)App.Current.FindResource(GEOCODE_RESULT_ZOOMED_RESOURCE_NAME);

            StringBuilder stringBuilder = new StringBuilder();

            // Add "Not located, but zoomed to..." string.
            stringBuilder.AppendFormat(messageFmt, item.ToString());

            // Add zoomed address.
            string zoomedAddress = GeocodeHelpers.GetZoomedAddress(item, candidateToZoom);

            stringBuilder.Append(zoomedAddress);

            // Add dot at the end of sentence.
            stringBuilder.Append(MESSAGE_STRING_PARTS_DELIMETER);

            // Add "Use pushpin" string.
            stringBuilder.Append((string)App.Current.FindResource(USE_PUSHPIN_RESOURCE_NAME));

            string result = stringBuilder.ToString();

            return(result);
        }
        /// <summary>
        /// Save manual order geocoding results to local storage.
        /// </summary>
        /// <param name="geocodable">Geocoding object.</param>
        /// <param name="oldAddress">Address before geocoding.</param>
        private void _SaveToLocalAddressNameStorage(IGeocodable geocodable, Address oldAddress)
        {
            // Do nothing in case of geocodable object is location.
            Order order = geocodable as Order;
            if (order != null)
            {
                NameAddressRecord nameAddressRecord = CommonHelpers.CreateNameAddressPair(order, oldAddress);

                // Do save in local storage.
                App.Current.NameAddressStorage.InsertOrUpdate(nameAddressRecord,
                    App.Current.Geocoder.AddressFormat);
            }
        }
        /// <summary>
        /// Get candidates from not primary sublocators. City, Zip, Street candidates.
        /// </summary>
        /// <param name="geocodable">Geocodable object to validation</param>
        /// <param name="candidatesIncludedDisabledLocators">Candidates from all locators.</param>
        /// <returns>City, Zip, Street candidates.</returns>
        public static IEnumerable <AddressCandidate> GetBestCandidatesFromNotPrimaryLocators(IGeocoder geocoder,
                                                                                             IGeocodable geocodable, IEnumerable <AddressCandidate> candidatesIncludedDisabledLocators)
        {
            Debug.Assert(geocodable != null);
            Debug.Assert(candidatesIncludedDisabledLocators != null);

            List <AddressCandidate> candidatesFromNotPrimaryLocators = new List <AddressCandidate>();

            // If current geocoder is ArcGiscomGeocoder.
            var arcgisgeocoder = geocoder as ArcGiscomGeocoder;

            if (arcgisgeocoder != null)
            {
                // If we have candidates - return first of them as a result.
                if (candidatesIncludedDisabledLocators.Any())
                {
                    candidatesFromNotPrimaryLocators.Add(candidatesIncludedDisabledLocators.First());
                }

                return(candidatesFromNotPrimaryLocators);
            }

            if (App.Current.Geocoder.IsCompositeLocator)
            {
                List <LocatorInfo> sublocators = new List <LocatorInfo>();
                sublocators.AddRange(App.Current.Geocoder.Locators);

                // Get best street candidate.
                List <LocatorInfo>      streetLocators   = _ExtractLocators(AddressPart.AddressLine, sublocators);
                List <AddressCandidate> streetCandidates = _GetStreetCandidates(geocodable, streetLocators, candidatesIncludedDisabledLocators);

                if (streetCandidates != null)
                {
                    candidatesFromNotPrimaryLocators.AddRange(streetCandidates);
                }

                if (candidatesFromNotPrimaryLocators.Count == 0)
                {
                    // Get best zip candidate.
                    List <LocatorInfo> zipLocators   = _ExtractLocators(AddressPart.PostalCode1, sublocators);
                    AddressCandidate   bestCandidate = _GetBestCandidateFromLocators(zipLocators, candidatesIncludedDisabledLocators);

                    if (bestCandidate == null)
                    {
                        // Get best cityState candidate.
                        List <LocatorInfo> cityStateLocators = _ExtractLocators(AddressPart.StateProvince, sublocators);
                        bestCandidate = _GetBestCandidateFromLocators(cityStateLocators, candidatesIncludedDisabledLocators);
                    }

                    if (bestCandidate != null)
                    {
                        candidatesFromNotPrimaryLocators.Add(bestCandidate);
                    }
                }
            }

            return(candidatesFromNotPrimaryLocators);
        }
        /// <summary>
        /// Get geocode result for subpage.
        /// </summary>
        /// <param name="item">Geocoded item.</param>
        /// <param name="context">Candidates to zoom.</param>
        /// <returns>Current geocode process result.</returns>
        public string GetGeocodeResultString(IGeocodable item, object context)
        {
            if (item == null)
                return string.Empty;

            AddressCandidate[] candidatesToZoom = context as AddressCandidate[];

            string result;
            if (candidatesToZoom == null || candidatesToZoom.Length == 0)
            {
                result = _MakeNotFoundString(item);
            }
            else
            {
                result = _MakeNotFoundButZoomedString(item, candidatesToZoom[0]);
            }

            return result;
        }
        /// <summary>
        /// Make reverse geocode request and fill geocodable object with new address fields values.
        /// </summary>
        /// <param name="geocodable">Geocodable to fill.</param>
        /// <param name="location">Geolocation point for request.</param>
        /// <returns>Is responce was received.</returns>
        private bool _ProcessReverseGeocode(IGeocodable geocodable, ESRI.ArcLogistics.Geometry.Point location)
        {
            bool result = false;

            try
            {
                Address geocodedAddress = App.Current.Geocoder.ReverseGeocode(location);

                // In case of not empty response - fill address.
                if (geocodedAddress != null)
                {
                    geocodedAddress.CopyTo(geocodable.Address);
                }
                else
                {
                    geocodable.Address.MatchMethod = (string)App.Current.FindResource(MANUALLY_EDITED_XY_FAR_FROM_NEAREST_ROAD_RESOURCE_NAME);
                }

                result = true;
            }
            catch (Exception ex)
            {
                if (ex is AuthenticationException || ex is CommunicationException)
                {
                    string service = (string)App.Current.FindResource(GEOCODING_SERVICE_NAME_RESOURCE_NAME);
                    CommonHelpers.AddServiceMessage(service, ex);
                }
                else
                    throw;
            }

            return result;
        }
Exemple #31
0
        /// <summary>
        /// Show popup with geocoded address.
        /// </summary>
        /// <param name="e">Reverse geocoding completed event args.</param>
        private void _ShowAddress(AsyncReverseGeocodedEventArgs e)
        {
            IGeocodable geocodable = _GetCurrentGeocodableObject(_mapControl);

            System.Windows.Point initialPoint = (System.Windows.Point)e.UserState;

            if (geocodable != null && _enabled && _mapControl.LastCursorPos.HasValue &&
                _mapControl.LastCursorPos.Value.X == initialPoint.X &&
                _mapControl.LastCursorPos.Value.Y == initialPoint.Y)
            {
                Point cursorPos = _mapControl.LastCursorPos.Value;

                _HideAddressPopups();

                Rect mapRect = new Rect(0, 0, _mapControl.map.ActualWidth, _mapControl.map.ActualHeight);

                Point objectLocation = _ConvertToScreenPos(e.Location);

                // Create canvas with dotted line.
                Canvas canvas = _CreateDottedLineCanvas(objectLocation, _mapControl.LastCursorPos.Value);

                // Get coordinates of top left of canvas.
                double canvasLeft = cursorPos.X;
                if (objectLocation.X < canvasLeft)
                {
                    canvasLeft = objectLocation.X;
                }

                double canvasTop = cursorPos.Y;
                if (objectLocation.Y < canvasTop)
                {
                    canvasTop = objectLocation.Y;
                }

                Rect canvasRect = new System.Windows.Rect(canvasLeft,
                                                          canvasTop, canvas.Width, canvas.Height);

                if (mapRect.Contains(canvasRect))
                {
                    canvasRect.Offset(0, -canvasRect.Height);

                    _dottedLinePopup = _CreatePopup(null, canvas, canvasRect);

                    Point popupPosition = _ConvertToScreenPos(e.Location);

                    // Show ellipse popup in position of reverse geocoded object.
                    Rect ellipseRect = new System.Windows.Rect(popupPosition.X - _sizeOfEllipse / 2,
                                                               popupPosition.Y - 3 * _sizeOfEllipse / 2, _popupWidth, _popupHeigth);
                    _ellipsePopup = _CreatePopup("MapPopupEllipseStyle", null, ellipseRect);

                    // Set cursor to popup. Cursor will be set on ellipse.
                    _ellipsePopup.Cursor = _mapControl.map.Cursor;

                    // Subscribe on mouse down to reraise mouse down on map.
                    _ellipsePopup.MouseDown += new MouseButtonEventHandler(_EllipsePopupMouseDown);

                    // Show address popup higher than IGeocodable object.
                    Rect addressRect = new System.Windows.Rect(popupPosition.X + _popupX,
                                                               popupPosition.Y - _popupY, _popupWidth, _popupHeigth);

                    string address = _GetAddressValue(e.Address);
                    _addressPopup = _CreatePopup("MapPopupStyle", address, addressRect);
                }
            }
        }
Exemple #32
0
 /// <summary>
 /// Do regeocoding
 /// </summary>
 /// <param name="location">Location to regeocode</param>
 public void StartGeocoding(IGeocodable location)
 {
     _geocodablePage.StartGeocoding(location);
 }
        /// <summary>
        /// Start geocoding.
        /// </summary>
        /// <param name="geocodable">Item to geocode.</param>
        /// <param name="useLocalAsPrimary">Is item just created.</param>
        private void _StartGeocoding(IGeocodable geocodable, bool useLocalAsPrimary)
        {
            CandidatesToZoom = null;

            _mapCtrl.HideZoomToCandidatePopup();

            // Do not need to start geocoding if geocodable object is far from road. Geocode will be failed.
            string farFromRoadMatchMethod = (string)App.Current.FindResource(MANUALLY_EDITED_XY_FAR_FROM_NEAREST_ROAD_RESOURCE_NAME);
            if (geocodable.Address.MatchMethod != null &&
                geocodable.Address.MatchMethod.Equals(farFromRoadMatchMethod, StringComparison.OrdinalIgnoreCase))
            {
                return;
            }

            // If try to geocode with edited address fields during another geocoding process.
            if (IsGeocodingInProcess)
            {
                _candidateSelect.CandidateChanged -= new EventHandler(_CandidateChanged);
                _Clear();
                _candidateSelect.CandidateChanged += new EventHandler(_CandidateChanged);
            }

            IsGeocodingInProcess = true;

            if (GeocodingStarted != null)
            {
                GeocodingStarted(this, EventArgs.Empty);
            }

            List<AddressCandidate> candidates = GeocodeHelpers.DoGeocode(geocodable, useLocalAsPrimary, true);
            var minimumMatchScore = App.Current.Geocoder.MinimumMatchScore;

            _ProcessGeocodingResults(geocodable, candidates, minimumMatchScore);

            _isAddressChanged = false;
        }
        /// <summary>
        /// Finish geocoding and try to zoom near.
        /// </summary>
        /// <param name="geocoder">Geocoder which found candidates.</param>
        /// <param name="geocodable">Item to geocode.</param>
        /// <param name="allCandidates">All candidates, returned for current geocoded item.</param>
        private void _ProcessCandidatesNotFound(IGeocoder geocoder, IGeocodable geocodable,
            IEnumerable<AddressCandidate> allCandidates)
        {
            // Set candidates to zoom.
            var candidatesFromNotPrimaryLocators =
                GeocodeHelpers.GetBestCandidatesFromNotPrimaryLocators(geocoder, geocodable, allCandidates);
            CandidatesToZoom = candidatesFromNotPrimaryLocators.ToArray();

            if (CandidatesNotFound != null)
                CandidatesNotFound(this, EventArgs.Empty);

            AddressCandidate zoomedCandidate = null;
            // Zoom to candidates from not primary locators.
            if (CandidatesToZoom != null && CandidatesToZoom.Length > 0)
            {
                MapExtentHelpers.ZoomToCandidates(_mapCtrl, CandidatesToZoom);
                zoomedCandidate = CandidatesToZoom[0];
            }

            // Show popup on map if not in fleet wizard.
            if (!ParentIsFleetWisard)
                _mapCtrl.ShowZoomToCandidatePopup(geocodable, CandidatesToZoom);

            IsGeocodingInProcess = false;
        }
        /// <summary>
        /// React on new item commited.
        /// </summary>
        public void OnNewItemCommitted()
        {
            Debug.Assert(_currentItem != null);

            _canceledByGrid = true;
            EditEnded(false);
            _currentItem.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged);
            _canceledByGrid = false;

            _SetAddressByPointToolEnabled(false);

            _currentItem = null;
        }
        /// <summary>
        /// React on cancelling new item.
        /// </summary>
        public void OnNewItemCancelling()
        {
            Debug.Assert(_parentLayer != null);

            // Supporting API issues. Needed in case of external new item creating canceling.
            if (_currentItem == null)
                return;

            _canceledByGrid = true;

            ObjectLayer.DeleteObject(_currentItem, _parentLayer.MapLayer);
            EditEnded(false);
            _currentItem.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged);

            if (IsGeocodingInProcess)
            {
                _EndGeocoding(false);
            }
            else
            {
                _currentItem = null;
            }

            _canceledByGrid = false;

            _SetAddressByPointToolEnabled(false);
        }
        /// <summary>
        /// Process geocoding result.
        /// </summary>
        /// <param name="geocodable">Item to geocode.</param>
        /// <param name="allCandidates">Candidates list from all locators, include not primary.</param>
        /// <param name="minimumMatchScore">Specifies the minimum score value at which candidate
        /// will be treated as matched.</param>
        private void _ProcessGeocodingResults(
            IGeocodable geocodable,
            List<AddressCandidate> allCandidates,
            int minimumMatchScore)
        {
            _ProcessGeocodingCandidates(allCandidates, geocodable, minimumMatchScore);

            if (IsGeocodingInProcess)
            {
                _ExpandCandidateSelect();
                _SetMapviewToCandidates();
                _mapCtrl.SetEditingMapLayersOpacity(true);

                // React on map size changing only if map is initialized.
                if (_mapCtrl.Map.IsInitialized())
                    _mapCtrl.map.SizeChanged += new SizeChangedEventHandler(_MapSizeChanged);
            }
            else
            {
                // In case of we have geocode candidates at start, but with newly address data we haven't.
                _CollapseCandidateSelect();

                // Current item can be not null only in case of geocoding in progress or editing in progress.
                if (!_geocodableGrid.IsItemBeingEdited)
                    _currentItem = null;
            }
        }
        /// <summary>
        /// React on commiting edit.
        /// </summary>
        /// <param name="args">Commiting event args.</param>
        /// <param name="canStartGeocoding">Flag for accepting geocoding start.</param>
        public void OnCommittingEdit(DataGridItemCancelEventArgs args, bool canStartGeocoding)
        {
            Debug.Assert(args != null);

            _canceledByGrid = true;
            IGeocodable geocodable = (IGeocodable)args.Item;
            if (geocodable != _currentItem)
            {
                args.Cancel = true;
            }

            if (_isAddressChanged && canStartGeocoding)
            {
                _StartGeocoding(_currentItem, true);
                if (!IsGeocodingInProcess)
                {
                    _currentItem.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged);
                }
            }

            EditEnded(false);

            _canceledByGrid = false;

            if (!IsGeocodingInProcess)
            {
                _currentItem = null;
            }
        }
        /// <summary>
        /// React on beginning edit.
        /// </summary>
        /// <param name="args">Beginning edit args.</param>
        public void OnBeginningEdit(DataGridItemCancelEventArgs args)
        {
            Debug.Assert(args != null);

            // if geocoding in process and try to edit not geocoding geocodable object - than cancel it
            IGeocodable current = (IGeocodable)args.Item;

            // in case of deleting edited - cancel beginning edit
            if ((IsGeocodingInProcess && current != _currentItem))
            {
                args.Cancel = true;
            }
            else
            {
                _currentItem = args.Item as IGeocodable;
                _currentItem.Address.PropertyChanged += new PropertyChangedEventHandler(_AddressPropertyChanged);

                _editStartedByGrid = true;
                _StartEdit(_currentItem);
                _editStartedByGrid = false;
            }
        }
        /// <summary>
        /// End geocoding.
        /// </summary>
        /// <param name="needToCancelEdit">Is need to cancel edit. Is used because
        /// on "cancelling new item" call "cancelling new item" again.</param>
        private void _EndGeocoding(bool needToCancelEdit)
        {
            Debug.Assert(_mapCtrl != null);

            Debug.Assert(IsGeocodingInProcess);

            _mapCtrl.IgnoreSizeChanged = true;

            // Workaround - see method comment.
            CommonHelpers.FillAddressWithSameValues(_currentItem.Address);

            _mapCtrl.SetEditingMapLayersOpacity(false);

            IsGeocodingInProcess = false;
            _isAddressChanged = false;
            _parentLayer.Selectable = true;
            _Clear();
            _CollapseCandidateSelect();
            if (_currentItem != null)
            {
                _currentItem.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged);
            }

            if (App.Current.Project != null)
            {
                App.Current.Project.Save();
            }

            // End edit in data grid.
            if (needToCancelEdit &&
                !_canceledByGrid &&
                _geocodableGrid.IsItemBeingEdited)
            {
                _EndEditInGrid();
            }

            _currentItem = null;
        }
        /// <summary>
        /// Do regeocoding.
        /// </summary>
        /// <param name="geocodable">Geocodable to regeocode.</param>
        public void StartGeocoding(IGeocodable geocodable)
        {
            Debug.Assert(geocodable != null);

            _currentItem = geocodable;
            _StartGeocoding(geocodable, false);
        }
        /// <summary>
        /// If address is empty show message.
        /// </summary>
        /// <param name="geocodable">Geocodable item.</param>
        private void _ShowReverseGeocodingErrorMessage(IGeocodable geocodable)
        {
            string name = string.Empty;
            string formatStr = string.Empty;

            // Extract name and format string.
            Order order = geocodable as Order;
            Location location = geocodable as Location;
            if (order != null)
            {
                name = order.Name;
                formatStr = (string)App.Current.FindResource(ORDER_FAR_FROM_ROAD_RESOURCE_NAME);
            }
            else if (location != null)
            {
                name = location.Name;
                formatStr = (string)App.Current.FindResource(LOCATION_FAR_FROM_ROAD_RESOURCE_NAME);
            }
            else
            {
                // Geocodable object must be order or location.
                Debug.Assert(false);
            }

            if (!string.IsNullOrEmpty(formatStr))
            {
                // Show error.
                string message = string.Format(formatStr, name);
                App.Current.Messenger.AddError(message);
            }
        }
        /// <summary>
        /// Validates and fixes candidates with incorrect locations.
        /// </summary>
        /// <param name="candidates">The reference to the collection of address candidates to
        /// be validated and fixed.</param>
        /// <param name="geocodable">The reference to the geocodable object used for retrieving
        /// candidates collection.</param>
        /// <returns>A reference to the collection of address candidates with fixed
        /// locations.</returns>
        private IEnumerable<AddressCandidate> _GetValidLocations(
            IEnumerable<AddressCandidate> candidates,
            IGeocodable geocodable)
        {
            Debug.Assert(candidates != null);
            Debug.Assert(candidates.All(candidate => candidate != null));
            Debug.Assert(geocodable != null);

            List<int> incorrectCandidates = new List<int>();

            try
            {
                var streetsGeocoder = App.Current.StreetsGeocoder;
                var locationValidator = new LocationValidator(streetsGeocoder);

                incorrectCandidates = locationValidator
                    .FindIncorrectLocations(candidates)
                    .ToList();
            }
            catch (Exception ex)
            {
                if (GeocodeHelpers.MustThrowException(ex))
                {
                    throw;
                }
            }

            if (!incorrectCandidates.Any())
            {
                return candidates;
            }

            // Get incorrect address candidates.
            List<AddressCandidate> allCandidates = candidates.ToList();
            var invalidAddressCandidates = incorrectCandidates
                .Select(index => allCandidates[index])
                .ToList();

            // Get all candidates which is not invalid.
            var result = candidates
                .Except(invalidAddressCandidates)
                .ToList();

            return result;
        }
        /// <summary>
        /// Processes geocoding candidates.
        /// </summary>
        /// <param name="allCandidates">The reference to a collection of all geocoding
        /// candidates.</param>
        /// <param name="geocodable">The reference to an object to be geocoded.</param>
        /// <param name="minimumMatchScore">Specifies the minimum score value at which candidate
        /// will be treated as matched.</param>
        private void _ProcessGeocodingCandidates(
            IEnumerable<AddressCandidate> allCandidates,
            IGeocodable geocodable,
            int minimumMatchScore)
        {
            Debug.Assert(allCandidates != null);
            Debug.Assert(allCandidates.All(candidate => candidate != null));
            Debug.Assert(geocodable != null);

            var candidates = GeocodeHelpers.SortCandidatesByPrimaryLocators(
                App.Current.Geocoder,
                allCandidates);

            if (!candidates.Any())
            {
                _ProcessCandidatesNotFound(App.Current.Geocoder, geocodable, allCandidates.ToList());

                return;
            }

            candidates = _GetValidLocations(candidates, geocodable).ToList();

            var distinctCandidates = _FilterSameCandidates(candidates, minimumMatchScore).ToList();

            var matchedCandidates = distinctCandidates
                .Where(candidate => candidate.Score >= minimumMatchScore)
                .ToList();

            if (matchedCandidates.Count == 1)
            {
                _ProcessMatchFound(geocodable, matchedCandidates.First());
            }
            else if (matchedCandidates.Count > 0)
            {
                // Find candidates with 100% score.
                var maxScoreCandidates = matchedCandidates
                    .Where(candidate => candidate.Score == 100)
                    .ToList();

                if (maxScoreCandidates.Count == 1)
                    // If found ONE candidate with 100% score, then choose it.
                    _ProcessMatchFound(geocodable, maxScoreCandidates.First());
                else
                    // If not found 100% candidates or found more than ONE, show candidates.
                    _ProcessCandidatesFound(matchedCandidates);
            }
            else
            {
                var topCandidates = distinctCandidates
                    .OrderByDescending(candidate => candidate.Score)
                    .Take(MAX_CANDIDATE_COUNT)
                    .ToList();

                if (topCandidates.Count > 0)
                    _ProcessCandidatesFound(topCandidates);
                else
                    _ProcessCandidatesNotFound(App.Current.Geocoder, geocodable, allCandidates);
            }
        }
 /// <summary>
 /// Show hint "Could not located, but zoomed..."
 /// </summary>
 /// <param name="geocodableItem">Geocodable object.</param>
 /// <param name="candidatesToZoom">Address to which map was zoomed. Null if not zoomed.</param>
 public void ShowZoomToCandidatePopup(IGeocodable geocodableItem, AddressCandidate[] candidatesToZoom)
 {
     if (_isGeocodingHintInitialized)
     {
         // Show hint suspendedly because final selection changed event in datagrid control is suspended.
         // And so hint will be hided on selection changed.
         Dispatcher.BeginInvoke(new Action(delegate()
             {
                 if (SelectedItems.Count > 0 && SelectedItems[0] == geocodableItem)
                 {
                     GeocodingHint.ShowHint(geocodableItem, candidatesToZoom);
                 }
             }), DispatcherPriority.Background);
     }
 }
        /// <summary>
        /// Do geocode of geocodable object.
        /// </summary>
        /// <param name="geocodable">Item to geocode.</param>
        /// <param name="useLocalAsPrimary">Is item just created.</param>
        /// <param name="includeDisabledLocators">Is need to add candidates from disabled locators.</param>
        /// <returns>Candidates list.</returns>
        public static List<AddressCandidate> DoGeocode(IGeocodable geocodable, bool useLocalAsPrimary, bool includeDisabledLocators)
        {
            List<AddressCandidate> candidates = null;

            App.Current.MainWindow.Cursor = Cursors.Wait;

            try
            {
                Order order = geocodable as Order;
                Location location = geocodable as Location;
                if (order != null)
                {
                    candidates = _DoLocalOrderGeocode(order, useLocalAsPrimary, includeDisabledLocators);
                }
                else if (location != null)
                {
                    candidates = _DoGeocodeLocation(location, includeDisabledLocators);
                }
            }
            catch (Exception ex)
            {
                if (MustThrowException(ex))
                {
                    throw;
                }
            }
            finally
            {
                App.Current.MainWindow.Cursor = Cursors.Arrow;
            }

            if (candidates == null)
            {
                candidates = new List<AddressCandidate>();
            }

            return candidates;
        }
        /// <summary>
        /// Get candidates from not primary sublocators. City, Zip, Street candidates.
        /// </summary>
        /// <param name="geocodable">Geocodable object to validation</param>
        /// <param name="candidatesIncludedDisabledLocators">Candidates from all locators.</param>
        /// <returns>City, Zip, Street candidates.</returns>
        public static IEnumerable<AddressCandidate> GetBestCandidatesFromNotPrimaryLocators(IGeocoder geocoder,
            IGeocodable geocodable, IEnumerable<AddressCandidate> candidatesIncludedDisabledLocators)
        {
            Debug.Assert(geocodable != null);
            Debug.Assert(candidatesIncludedDisabledLocators != null);

            List<AddressCandidate> candidatesFromNotPrimaryLocators = new List<AddressCandidate>();

            // If current geocoder is ArcGiscomGeocoder.
            var arcgisgeocoder = geocoder as ArcGiscomGeocoder;
            if (arcgisgeocoder != null)
            {
                // If we have candidates - return first of them as a result.
                if (candidatesIncludedDisabledLocators.Any())
                    candidatesFromNotPrimaryLocators.Add(candidatesIncludedDisabledLocators.First());

                return candidatesFromNotPrimaryLocators;
            }

            if (App.Current.Geocoder.IsCompositeLocator)
            {
                List<LocatorInfo> sublocators = new List<LocatorInfo>();
                sublocators.AddRange(App.Current.Geocoder.Locators);

                // Get best street candidate.
                List<LocatorInfo> streetLocators = _ExtractLocators(AddressPart.AddressLine, sublocators);
                List<AddressCandidate> streetCandidates = _GetStreetCandidates(geocodable, streetLocators, candidatesIncludedDisabledLocators);

                if (streetCandidates != null)
                    candidatesFromNotPrimaryLocators.AddRange(streetCandidates);

                if (candidatesFromNotPrimaryLocators.Count == 0)
                {
                    // Get best zip candidate.
                    List<LocatorInfo> zipLocators = _ExtractLocators(AddressPart.PostalCode1, sublocators);
                    AddressCandidate bestCandidate = _GetBestCandidateFromLocators(zipLocators, candidatesIncludedDisabledLocators);

                    if (bestCandidate == null)
                    {
                        // Get best cityState candidate.
                        List<LocatorInfo> cityStateLocators = _ExtractLocators(AddressPart.StateProvince, sublocators);
                        bestCandidate = _GetBestCandidateFromLocators(cityStateLocators, candidatesIncludedDisabledLocators);
                    }

                    if (bestCandidate != null)
                    {
                        candidatesFromNotPrimaryLocators.Add(bestCandidate);
                    }
                }
            }

            return candidatesFromNotPrimaryLocators;
        }
        /// <summary>
        /// Make string parts like 'We couldn’t find… so we’ve zoomed to…'
        /// If street candidate - use Address Line from geocodable item, otherwise(citystate or zip) use full address.
        /// </summary>
        /// <param name="item">Geocodable item.</param>
        /// <param name="candidateToZoom">First candidate to zoom.</param>
        /// <returns>Geocode result string parts.</returns>
        public static string GetZoomedAddress(IGeocodable item, AddressCandidate candidateToZoom)
        {
            LocatorType? locatorType = GeocodeHelpers.GetLocatorTypeOfCandidate(candidateToZoom);

            string zoomedAddress;

            // If locator type of candidate is street than get Address Line.
            if (locatorType.HasValue && locatorType.Value == LocatorType.Street &&
                !string.IsNullOrEmpty(item.Address.AddressLine))
            {
                // Extract street name.
                zoomedAddress = GeocodeHelpers.ExtractStreet(item.Address.AddressLine);
            }
            else
            {
                // Otherwise use full address.
                zoomedAddress = candidateToZoom.Address.FullAddress;
            }

            return zoomedAddress;
        }
        /// <summary>
        /// Make string like 'Bevmo could not be found in Redlands,CA.'
        /// </summary>
        /// <param name="item">Geocodable item.</param>
        /// <returns>Geocode result string.</returns>
        private string _MakeNotFoundString(IGeocodable item)
        {
            string resultFmt = (string)App.Current.FindResource(GEOCODE_RESULT_RESOURCE_NAME);

            string cityStateString = string.Empty;

            // Use both fields if both not empty. Use not empty otherwise.
            if (!string.IsNullOrEmpty(item.Address.Locality3) && !string.IsNullOrEmpty(item.Address.StateProvince))
            {
                cityStateString = string.Format(CITY_STATE_FMT, item.Address.Locality3, item.Address.StateProvince);
            }
            else if (!string.IsNullOrEmpty(item.Address.Locality3))
            {
                cityStateString = item.Address.Locality3;
            }
            else if (!string.IsNullOrEmpty(item.Address.StateProvince))
            {
                cityStateString = item.Address.StateProvince;
            }

            string inString = string.Empty;

            // If city or state present - make "in" string.
            if (!string.IsNullOrEmpty(cityStateString))
            {
                inString = string.Format((string)App.Current.FindResource(IN_ADDRESS_RESOURCE_NAME), cityStateString);
            }

            string result = string.Format(resultFmt, item.ToString(), inString);

            return result;
        }
        /// <summary>
        /// Is locator address fields empty.
        /// </summary>
        /// <param name="geocodable">Geocodable object.</param>
        /// <returns>Is locator address fields empty.</returns>
        public static bool IsActiveAddressFieldsEmpty(IGeocodable geocodable)
        {
            bool isEmpty = true;

            foreach (AddressField addressField in App.Current.Geocoder.AddressFields)
            {
                if (!string.IsNullOrEmpty(geocodable.Address[addressField.Type]))
                {
                    isEmpty = false;
                    break;
                }
            }

            return isEmpty;
        }
        /// <summary>
        /// Make string like 'Bevmo couldn’t be located, we’ve zoomed to Pat’s Ranch Rd.  Use the pushpin tool to locate exactly.'
        /// If street candidate - use Address Line from geocodable item, otherwise(citystate or zip) use full address.
        /// </summary>
        /// <param name="item">Geocodable item.</param>
        /// <param name="candidateToZoom">First candidate to zoom.</param>
        /// <returns>Geocode result string.</returns>
        private string _MakeNotFoundButZoomedString(IGeocodable item, AddressCandidate candidateToZoom)
        {
            string messageFmt = (string)App.Current.FindResource(GEOCODE_RESULT_ZOOMED_RESOURCE_NAME);

            StringBuilder stringBuilder = new StringBuilder();

            // Add "Not located, but zoomed to..." string.
            stringBuilder.AppendFormat(messageFmt, item.ToString());

            // Add zoomed address.
            string zoomedAddress = GeocodeHelpers.GetZoomedAddress(item, candidateToZoom);
            stringBuilder.Append(zoomedAddress);

            // Add dot at the end of sentence.
            stringBuilder.Append(MESSAGE_STRING_PARTS_DELIMETER);

            // Add "Use pushpin" string.
            stringBuilder.Append((string)App.Current.FindResource(USE_PUSHPIN_RESOURCE_NAME));

            string result = stringBuilder.ToString();

            return result;
        }
        /// <summary>
        /// Set geocoded fields to address.
        /// </summary>
        /// <param name="geocodable">Geocodable object to set address and position.</param>
        /// <param name="candidate">Source candidate.</param>
        public static void SetCandidate(IGeocodable geocodable, AddressCandidate candidate)
        {
            Debug.Assert(geocodable != null);
            Debug.Assert(candidate != null);

            // Set geolocation.
            geocodable.GeoLocation = new ESRI.ArcLogistics.Geometry.Point(
                candidate.GeoLocation.X, candidate.GeoLocation.Y);
            geocodable.Address.MatchMethod = candidate.Address.MatchMethod ?? string.Empty;

            if (App.Current.Geocoder.AddressFormat == AddressFormat.MultipleFields)
            {
                // Concatenate Full Address from other address fields.
                SetFullAddress(geocodable.Address);
            }
            else if (App.Current.Geocoder.AddressFormat == AddressFormat.SingleField)
            {
                // Do nothing: don't touch user entered\imported Full Address
                // and can't parse Full Address to address parts.
            }
            else
            {
                // Do nothing.
                Debug.Assert(false);
            }
        }
        /// <summary>
        /// Check is location of geocodable object valid and replace it by candidate from local
        /// geocoder if exists.
        /// </summary>
        /// <param name="geocodable">Geocodable object to check.</param>
        /// <returns>Is geocodable object valid.</returns>
        private bool _SourceGeocodedObject(IGeocodable geocodable)
        {
            Debug.Assert(null != geocodable); // created

            bool isObjectGeocoded = false;

            // First check if name address pair exists in local geocoder database.
            // If exists - overwrite geolocation and address from it.
            App currentApp = App.Current;
            var localGeocoder =
                new LocalGeocoder(currentApp.Geocoder, currentApp.NameAddressStorage);

            var nameAddress = new NameAddress();
            nameAddress.Name = geocodable.ToString();
            nameAddress.Address = geocodable.Address.Clone() as Address;

            AddressCandidate localCandidate = localGeocoder.Geocode(nameAddress);
            if (localCandidate == null)
            {   // Update from internal object information.
                AppGeometry.Envelope extent = currentApp.Map.ImportCheckExtent;
                if (extent.IsPointIn(geocodable.GeoLocation.Value))
                {
                    geocodable.Address.MatchMethod =
                        currentApp.FindString("ImportSourceMatchMethod");
                    isObjectGeocoded = true;

                    // Full address property must be combined from other fields, because
                    // it is not importing field.
                    if (App.Current.Geocoder.AddressFormat == AddressFormat.MultipleFields)
                        GeocodeHelpers.SetFullAddress(geocodable.Address);
                    else
                    {
                        // Do nothing: do not update full address since
                        // it is used for geocoding in Single Address Field Format.
                    }
                }
                // Else could not locate object using X/Y attributes - need geocode.
            }
            else
            {   // Init from local candidate.
                // Set location.
                geocodable.GeoLocation = new AppGeometry.Point(localCandidate.GeoLocation.X,
                                                               localCandidate.GeoLocation.Y);
                // Set address.
                localCandidate.Address.CopyTo(geocodable.Address);

                isObjectGeocoded = true;
            }

            return isObjectGeocoded;
        }
        /// <summary>
        /// Get street candidate. Extract street name, check that part of street name wasn't removed and try to geocode.
        /// </summary>
        /// <param name="geocodable">Geocodable object to geocode,</param>
        /// <param name="streetLocators">Street locators.</param>
        /// <param name="candidatesIncludedDisabledLocators">Geocoded candidates.</param>
        /// <returns>Street candidate.</returns>
        private static List<AddressCandidate> _GetStreetCandidates(
            IGeocodable geocodable,
            IEnumerable<LocatorInfo> streetLocators,
            IEnumerable<AddressCandidate> candidatesIncludedDisabledLocators)
        {
            Debug.Assert(geocodable != null);
            Debug.Assert(streetLocators != null);
            Debug.Assert(candidatesIncludedDisabledLocators != null);

            List<AddressCandidate> streetCandidates = null;

            if (!string.IsNullOrEmpty(geocodable.Address.AddressLine))
            {
                string street = _ExtractStreet(geocodable.Address.AddressLine);
                if (!street.Equals(geocodable.Address.AddressLine, StringComparison.OrdinalIgnoreCase))
                {
                    // If number removed from street address check that number wasn't part of street name. For example "8th ave".
                    ICloneable cloneableItem = geocodable as ICloneable;
                    IGeocodable geocodableWithoutHouseNumber = (IGeocodable)cloneableItem.Clone();

                    geocodableWithoutHouseNumber.Address.AddressLine = street;

                    // Get candidates for address with removed number.
                    List<AddressCandidate> candidatesForRemovedHouseNumber = DoGeocode(geocodableWithoutHouseNumber, true, false);
                    List<AddressCandidate> streetCandidatesForRemovedHouseNumber = _GetCandidatesFromLocators(streetLocators, candidatesForRemovedHouseNumber);

                    // If best candidate from street locator exists - use it.
                    if (streetCandidatesForRemovedHouseNumber.Count > 0)
                    {
                        streetCandidates = streetCandidatesForRemovedHouseNumber;
                    }
                }
            }

            // If street candidate not set yet - find best candidate from already geocoded candidates.
            if (streetCandidates == null)
            {
                streetCandidates = _GetCandidatesFromLocators(streetLocators, candidatesIncludedDisabledLocators);
            }

            // Fill address fields of street candidate.
            foreach (AddressCandidate candidate in streetCandidates)
            {
                ParseAndFillAddress(candidate.Address);
            }

            return streetCandidates;
        }
        /// <summary>
        /// React on creating new item.
        /// </summary>
        /// <param name="args">New item creating args.</param>
        public void OnCreatingNewItem(DataGridCreatingNewItemEventArgs args)
        {
            Debug.Assert(_parentLayer != null);
            Debug.Assert(args != null);

            _currentItem = (IGeocodable)args.NewItem;
            _currentItem.Address.PropertyChanged += new PropertyChangedEventHandler(_AddressPropertyChanged);

            Graphic graphic = _parentLayer.CreateGraphic(_currentItem);
            _parentLayer.MapLayer.Graphics.Add(graphic);

            _editStartedByGrid = true;
            _StartEdit(_currentItem);
            _editStartedByGrid = false;

            _SetAddressByPointToolEnabled(true);
        }
        /// <summary>
        /// End geocoding with match found. Save candidate position to edited item.
        /// </summary>
        /// <param name="geocodable">Item to geocode.</param>
        /// <param name="candidate">Matched candidate.</param>
        private void _ProcessMatchFound(IGeocodable geocodable, AddressCandidate candidate)
        {
            string manuallyEditedXY = (string)Application.Current.FindResource("ManuallyEditedXY");

            if (string.Equals(candidate.Address.MatchMethod, manuallyEditedXY))
            {
                geocodable.GeoLocation = new ESRI.ArcLogistics.Geometry.Point(candidate.GeoLocation.X, candidate.GeoLocation.Y); ;
                candidate.Address.CopyTo(geocodable.Address);
            }
            else
            {
                GeocodeHelpers.SetCandidate(geocodable, candidate);
            }

            if (MatchFound != null)
                MatchFound(this, EventArgs.Empty);

            IsGeocodingInProcess = false;
        }
        /// <summary>
        /// React on cancelling edit.
        /// </summary>
        /// <param name="args">Datagrid item args.</param>
        public void OnEditCanceled(DataGridItemEventArgs args)
        {
            Debug.Assert(args != null);

            _canceledByGrid = true;

            if (IsGeocodingInProcess)
            {
                _EndGeocoding(false);
            }

            IGeocodable geocodable = args.Item as IGeocodable;
            geocodable.Address.PropertyChanged -= new PropertyChangedEventHandler(_AddressPropertyChanged);
            _currentItem = null;
            _isAddressChanged = false;
            EditEnded(false);

            _canceledByGrid = false;
        }
 /// <summary>
 /// Do regeocoding
 /// </summary>
 /// <param name="location">Location to regeocode</param>
 public void StartGeocoding(IGeocodable location)
 {
     _geocodablePage.StartGeocoding(location);
 }