Imports System.Collections.Generic
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input
Imports ESRI.ArcGIS.Client
Imports ESRI.ArcGIS.Client.Geometry
Imports ESRI.ArcGIS.Client.Tasks
Namespace ArcGISWPFSDK
Partial Public Class RoutingDirections
Inherits UserControl
Private _routeTask As RouteTask
Private _locator As Locator
Private _stops As New List(Of Graphic)()
Private _activeSegmentGraphic As Graphic
Private _routeParams As RouteParameters
Private _directionsFeatureSet As DirectionsFeatureSet
Public Sub New()
InitializeComponent()
_routeParams = New RouteParameters() With { _
.ReturnRoutes = False, _
.ReturnDirections = True, _
.DirectionsLengthUnits = esriUnits.esriMiles, _
.Stops = _stops, _
.UseTimeWindows = False _
}
_routeTask = New RouteTask("http://tasks.arcgisonline.com/ArcGIS/rest/services/NetworkAnalysis/ESRI_Route_NA/NAServer/Route")
AddHandler _routeTask.SolveCompleted, AddressOf routeTask_SolveCompleted
AddHandler _routeTask.Failed, AddressOf task_Failed
_locator = New Locator("http://tasks.arcgisonline.com/ArcGIS/rest/services/Locators/TA_Address_NA/GeocodeServer")
AddHandler _locator.AddressToLocationsCompleted, AddressOf locator_AddressToLocationsCompleted
AddHandler _locator.Failed, AddressOf task_Failed
End Sub
Private Sub GetDirections_Click(sender As Object, e As RoutedEventArgs)
'Reset
DirectionsStackPanel.Children.Clear()
_stops.Clear()
TryCast(MyMap.Layers("MyRouteGraphicsLayer"), GraphicsLayer).ClearGraphics()
_locator.CancelAsync()
_routeTask.CancelAsync()
'Geocode from address
_locator.AddressToLocationsAsync(ParseAddress(FromTextBox.Text), "from")
End Sub
Private Sub locator_AddressToLocationsCompleted(sender As Object, e As AddressToLocationsEventArgs)
Dim graphicsLayer As GraphicsLayer = TryCast(MyMap.Layers("MyRouteGraphicsLayer"), GraphicsLayer)
If e.Results.Count > 0 Then
Dim address As AddressCandidate = e.Results(0)
Dim graphicLocation As New Graphic() With { _
.Geometry = address.Location _
}
graphicLocation.Attributes.Add("address", address.Address)
graphicLocation.Attributes.Add("score", address.Score)
_stops.Add(graphicLocation)
If DirectCast(e.UserState, String) = "from" Then
graphicLocation.Symbol = TryCast(LayoutRoot.Resources("FromSymbol"), ESRI.ArcGIS.Client.Symbols.Symbol)
'Geocode to address
_locator.AddressToLocationsAsync(ParseAddress(ToTextBox.Text), "to")
Else
graphicLocation.Symbol = TryCast(LayoutRoot.Resources("ToSymbol"), ESRI.ArcGIS.Client.Symbols.Symbol)
'Get route between from and to
_routeTask.SolveAsync(_routeParams)
End If
graphicsLayer.Graphics.Add(graphicLocation)
End If
End Sub
Private Sub routeTask_SolveCompleted(sender As Object, e As RouteEventArgs)
Dim graphicsLayer As GraphicsLayer = TryCast(MyMap.Layers("MyRouteGraphicsLayer"), GraphicsLayer)
Dim routeResult As RouteResult = e.RouteResults(0)
_directionsFeatureSet = routeResult.Directions
graphicsLayer.Graphics.Add(New Graphic() With { _
.Geometry = _directionsFeatureSet.MergedGeometry, _
.Symbol = TryCast(LayoutRoot.Resources("RouteSymbol"), ESRI.ArcGIS.Client.Symbols.Symbol) _
})
TotalDistanceTextBlock.Text = String.Format("Total Distance: {0}", FormatDistance(_directionsFeatureSet.TotalLength, "miles"))
TotalTimeTextBlock.Text = String.Format("Total Time: {0}", FormatTime(_directionsFeatureSet.TotalTime))
TitleTextBlock.Text = _directionsFeatureSet.RouteName
Dim i As Integer = 1
For Each graphic As Graphic In _directionsFeatureSet.Features
Dim text As New System.Text.StringBuilder()
text.AppendFormat("{0}. {1}", i, graphic.Attributes("text"))
If i > 1 AndAlso i < _directionsFeatureSet.Features.Count Then
Dim distance As String = FormatDistance(Convert.ToDouble(graphic.Attributes("length")), "miles")
Dim time As String = Nothing
If graphic.Attributes.ContainsKey("time") Then
time = FormatTime(Convert.ToDouble(graphic.Attributes("time")))
End If
If Not String.IsNullOrEmpty(distance) OrElse Not String.IsNullOrEmpty(time) Then
text.Append(" (")
End If
text.Append(distance)
If Not String.IsNullOrEmpty(distance) AndAlso Not String.IsNullOrEmpty(time) Then
text.Append(", ")
End If
text.Append(time)
If Not String.IsNullOrEmpty(distance) OrElse Not String.IsNullOrEmpty(time) Then
text.Append(")")
End If
End If
Dim textBlock As New TextBlock() With { _
.Text = text.ToString(), _
.Tag = graphic, _
.Margin = New Thickness(4), _
.Cursor = Cursors.Hand, _
.Foreground = New System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Black) _
}
AddHandler textBlock.MouseLeftButtonDown, New MouseButtonEventHandler(AddressOf directionsSegment_MouseLeftButtonDown)
DirectionsStackPanel.Children.Add(textBlock)
i += 1
Next
MyMap.ZoomTo(Expand(_directionsFeatureSet.Extent))
End Sub
Private Sub task_Failed(sender As Object, e As TaskFailedEventArgs)
Dim errorMessage As String = "Routing error: "
errorMessage += e.[Error].Message
For Each detail As String In TryCast(e.[Error], ServiceException).Details
errorMessage += "," & detail
Next
MessageBox.Show(errorMessage)
End Sub
Private Sub directionsSegment_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
Dim textBlock As TextBlock = TryCast(sender, TextBlock)
Dim feature As Graphic = TryCast(textBlock.Tag, Graphic)
MyMap.ZoomTo(Expand(feature.Geometry.Extent))
If _activeSegmentGraphic Is Nothing Then
_activeSegmentGraphic = New Graphic() With { _
.Symbol = TryCast(LayoutRoot.Resources("SegmentSymbol"), ESRI.ArcGIS.Client.Symbols.Symbol) _
}
Dim graphicsLayer As GraphicsLayer = TryCast(MyMap.Layers("MyRouteGraphicsLayer"), GraphicsLayer)
graphicsLayer.Graphics.Add(_activeSegmentGraphic)
End If
_activeSegmentGraphic.Geometry = feature.Geometry
End Sub
Private Sub StackPanel_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
If _directionsFeatureSet IsNot Nothing Then
Dim graphicsLayer As GraphicsLayer = TryCast(MyMap.Layers("MyRouteGraphicsLayer"), GraphicsLayer)
MyMap.ZoomTo(Expand(_directionsFeatureSet.Extent))
End If
End Sub
Private Function ParseAddress(address As String) As AddressToLocationsParameters
Dim fromArray As String() = address.Split(New Char() {","c})
Dim fromAddress As New AddressToLocationsParameters()
fromAddress.OutFields.Add("Loc_name")
fromAddress.Address.Add("Address", fromArray(0))
fromAddress.Address.Add("City", fromArray(1))
fromAddress.Address.Add("State", fromArray(2))
fromAddress.Address.Add("Zip", fromArray(3))
fromAddress.Address.Add("Country", "USA")
Return fromAddress
End Function
Private Function FormatDistance(dist As Double, units As String) As String
Dim result As String = ""
Dim formatDistance__1 As Double = Math.Round(dist, 2)
If formatDistance__1 <> 0 Then
result = formatDistance__1 & " " & units
End If
Return result
End Function
Private Function FormatTime(minutes As Double) As String
Dim time As TimeSpan = TimeSpan.FromMinutes(minutes)
Dim result As String = ""
Dim hours As Integer = CInt(Math.Truncate(Math.Floor(time.TotalHours)))
If hours > 1 Then
result = String.Format("{0} hours ", hours)
ElseIf hours = 1 Then
result = String.Format("{0} hour ", hours)
End If
If time.Minutes > 1 Then
result += String.Format("{0} minutes ", time.Minutes)
ElseIf time.Minutes = 1 Then
result += String.Format("{0} minute ", time.Minutes)
End If
Return result
End Function
Private Function Expand(e As Envelope) As Envelope
Dim factor As Double = 0.6
Dim centerMapPoint As MapPoint = e.GetCenter()
Return New Envelope(centerMapPoint.X - e.Width * factor, centerMapPoint.Y - e.Height * factor, centerMapPoint.X + e.Width * factor, centerMapPoint.Y + e.Height * factor)
End Function
End Class
End Namespace