Table of Contents

Source Code RoutingEdition ProjectTemplates CityRoutingAndDirections Wpf CS.zip

MainWindow.xaml

 <Window x:Class="ThinkGeo.MapSuite.RoutingExamples.MainWindow"  
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
         xmlns:local="clr-namespace:ThinkGeo.MapSuite.RoutingExamples"  
         xmlns:wpf="clr-namespace:ThinkGeo.MapSuite.WpfDesktopEdition;assembly=WpfDesktopEdition"  
         Title="City Routing and Directions"  
         Width="1155"  
         Height="675"  
         Icon="/CityRoutingAndDirections;Component/Image/MapSuite.ico"  
         Loaded="Window_Loaded"  
         WindowState="Maximized">  
     <Window.Resources>  
         <ResourceDictionary>  
             <local:CountToVisibilityConverter x:Key="CollectionToVisibilityConverter" />  
             <local:BooleanToReverseVisibilityConverter x:Key="BooleanToReverseVisibilityConverter" />  
             <local:PointShapeToStringConverter x:Key="PointShapeToStringConverter" />  
             <local:DistanceUnitToStringConverter x:Key="DistanceUnitToStringConverter" />  
             <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />  
         </ResourceDictionary>  
     </Window.Resources>  
     <Grid Style="{StaticResource body}">  
         <Grid.RowDefinitions>  
             <RowDefinition Height="auto" />  
             <RowDefinition Height="*" />  
             <RowDefinition Height="auto" />  
         </Grid.RowDefinitions>  
         <Border x:Name="Border"  
                 BorderThickness="0,0,0,5"  
                 CornerRadius="2"  
                 KeyboardNavigation.DirectionalNavigation="Contained"  
                 KeyboardNavigation.TabIndex="2"  
                 KeyboardNavigation.TabNavigation="Local"  
                 Padding="10">  
             <Border.Background>  
                 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">  
                     <LinearGradientBrush.GradientStops>  
                         <GradientStop Offset="0" Color="#ffffff" />  
                         <GradientStop Offset="0.4" Color="#fafafa" />  
                         <GradientStop Offset="0.55" Color="#f2f2f2" />  
                         <GradientStop Offset="0.6" Color="#f0f0f0" />  
                         <GradientStop Offset="0.9" Color="#e2e2e2" />  
                     </LinearGradientBrush.GradientStops>  
                 </LinearGradientBrush>  
             </Border.Background>  
             <Border.BorderBrush>  
                 <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">  
                     <LinearGradientBrush.GradientStops>  
                         <GradientStop Offset="0.85" Color="#5c707d" />  
                         <GradientStop Offset="1" Color="#305c707d" />  
                     </LinearGradientBrush.GradientStops>  
                 </LinearGradientBrush>  
             </Border.BorderBrush>  
             <StackPanel Orientation="Horizontal">  
                 <TextBlock Height="22"  
                            VerticalAlignment="Bottom"  
                            Style="{StaticResource h4}"  
                            Text="  Map Suite" />  
                 <TextBlock Style="{StaticResource h3}" Text=" City Routing and Directions" />  
             </StackPanel>  
         </Border>  
         <Grid Grid.Row="1">  
             <Grid.ColumnDefinitions>  
                 <ColumnDefinition Width="auto" />  
                 <ColumnDefinition Width="15" />  
                 <ColumnDefinition Width="*" />  
             </Grid.ColumnDefinitions>  
             <Grid x:Name="gridDockPanel"  
                   Grid.Column="0"  
                   Margin="5 0 0 0"  
                   HorizontalAlignment="Left"  
                   Visibility="{Binding ElementName=btnCollpaseToggle, Path=IsChecked, Converter={StaticResource BooleanToReverseVisibilityConverter}}">  
                 <Grid.RowDefinitions>  
                     <RowDefinition Height="auto" />  
                     <RowDefinition Height="*" />  
                 </Grid.RowDefinitions>  
                 <StackPanel Grid.Row="0" Orientation="Vertical">  
                     <TextBlock Width="290"  
                                Margin="0 10 0 5"  
                                VerticalAlignment="Center"  
                                Style="{StaticResource h4}"  
                                Text="Right click on the map to set up a route:"  
                                TextWrapping="Wrap" />  
                     <Grid>  
                         <Grid.RowDefinitions>  
                             <RowDefinition Height="auto" />  
                             <RowDefinition Height="auto" />  
                             <RowDefinition Height="auto" />  
                         </Grid.RowDefinitions>  
                         <Grid.ColumnDefinitions>  
                             <ColumnDefinition Width="auto" />  
                             <ColumnDefinition Width="auto" />  
                             <ColumnDefinition Width="auto" />  
                         </Grid.ColumnDefinitions>  
                         <Image Grid.Row="0"  
                                Grid.Column="0"  
                                Margin="4 0 0 0"  
                                Source="/CityRoutingAndDirections;Component/Image/start.png"  
                                Style="{StaticResource msImage}" />  
                         <TextBox x:Name="txtStart"  
                                  Grid.Row="0"  
                                  Grid.Column="1"  
                                  IsReadOnly="True"  
                                  Width="250"  
                                  Style="{StaticResource msTextbox}"  
                                  Text="{Binding StartPoint, Mode=TwoWay, Converter={StaticResource PointShapeToStringConverter}}" />  
                         <Button Grid.Row="0"  
                                 Grid.RowSpan="3"  
                                 Grid.Column="2"  
                                 Command="{Binding InverseDestinationCommand}"  
                                 Cursor="Hand"  
                                 ToolTip="Switch start and end search point"  
                                 Template="{StaticResource BorderlessButtonTemplate}"  
                                 Visibility="{Binding StopItems.Count, Converter={StaticResource CollectionToVisibilityConverter}}">  
                             <Image Source="/CityRoutingAndDirections;Component/Image/switch.png" Style="{StaticResource msButtonImage}" />  
                         </Button>  
                         <Image Grid.Row="2"  
                                Grid.Column="0"  
                                Margin="4 0 0 0"  
                                Source="/CityRoutingAndDirections;Component/Image/end.png"  
                                Style="{StaticResource msImage}" />  
                         <TextBox x:Name="txtEnd"  
                                  Grid.Row="2"  
                                  Grid.Column="1"  
                                  IsReadOnly="True"  
                                  Width="250"  
                                  Style="{StaticResource msTextbox}"  
                                  Text="{Binding EndPoint, Mode=TwoWay, Converter={StaticResource PointShapeToStringConverter}}" />  
                         <ItemsControl x:Name="lisLocations"  
                                       Grid.Row="1"  
                                       Grid.Column="0"  
                                       Grid.ColumnSpan="3"  
                                       Margin="4 0 0 0"  
                                       BorderBrush="Transparent"  
                                       ItemsSource="{Binding StopItems}"  
                                       Padding="0">  
                             <ItemsControl.ItemTemplate>  
                                 <DataTemplate>  
                                     <Grid>  
                                         <Grid.ColumnDefinitions>  
                                             <ColumnDefinition Width="auto" />  
                                             <ColumnDefinition Width="auto" />  
                                             <ColumnDefinition Width="auto" />  
                                         </Grid.ColumnDefinitions>  
                                         <Image Grid.Column="0"  
                                                Source="{Binding MarkerImageSource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  
                                                Style="{StaticResource msImage}" />  
                                         <TextBox Grid.Column="1"  
                                                  Width="250"  
                                                  IsReadOnly="True"  
                                                  Style="{StaticResource msTextbox}"  
                                                  Text="{Binding Location, Mode=TwoWay, Converter={StaticResource PointShapeToStringConverter}}" />  
                                         <Button Grid.Column="2"  
                                                 Command="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}, Path=DataContext.DeleteStopCommand}"  
                                                 CommandParameter="{Binding .}"  
                                                 Template="{StaticResource BorderlessButtonTemplate}">  
                                             <Image Source="/CityRoutingAndDirections;component/Image/remove.png" Style="{StaticResource msButtonImage}" />  
                                         </Button>  
                                     </Grid>  
                                 </DataTemplate>  
                             </ItemsControl.ItemTemplate>  
                         </ItemsControl>  
                     </Grid>  
 
                     <TextBlock Style="{StaticResource h4}" Text="Tools:" />  
                     <Border Margin="0 5 0 5"  
                             BorderBrush="LightGray"  
                             BorderThickness="1"  
                             CornerRadius="5">  
                         <StackPanel Margin="5" Orientation="Horizontal">  
                             <local:ImageRadioButton x:Name="rbtnPan"  
                                                     CheckImageSource="/CityRoutingAndDirections;component/Image/pan.png"  
                                                     Command="{Binding UpdateTrackModeCommand}"  
                                                     CommandParameter="None"  
                                                     ToolTip="Pan the map"  
                                                     IsChecked="True"  
                                                     Style="{StaticResource msRadioButton}" />  
                             <local:ImageRadioButton x:Name="rbtnPolygon"  
                                                     Margin="10 0 0 0"  
                                                     CheckImageSource="/CityRoutingAndDirections;component/Image/draw_polygon.png"  
                                                     Command="{Binding UpdateTrackModeCommand}"  
                                                     CommandParameter="Polygon"  
                                                     ToolTip="Draw areas to avoid traveling through"  
                                                     Style="{StaticResource msRadioButton}" />  
                             <Button Margin="10 0 0 0"  
                                     Command="{Binding UndoCommand}"  
                                     ToolTip="Undo last area drawn"  
                                     Template="{StaticResource BorderlessButtonTemplate}">  
                                 <Image Source="/CityRoutingAndDirections;component/Image/undo.png" Style="{StaticResource msButtonImage}" />  
                             </Button>  
                             <Button Margin="10 0 0 0"  
                                     Command="{Binding ClearBarriersCommand}"  
                                     ToolTip="Delete all areas"  
                                     Template="{StaticResource BorderlessButtonTemplate}">  
                                 <Image Source="/CityRoutingAndDirections;component/Image/clear.png" Style="{StaticResource msButtonImage}" />  
                             </Button>  
                         </StackPanel>  
                     </Border>  
 
                     <StackPanel HorizontalAlignment="Right" Orientation="Horizontal">  
                         <Button Command="{Binding CalculateDirectionCommand}"  
                                 Content="Get Directions"  
                                 Style="{StaticResource msButton}" />  
                         <Button Margin="0 5 0 5"  
                                 Command="{Binding ClearAllCommand}"  
                                 Content="Reset Route"  
                                 Style="{StaticResource msButton}" />  
                     </StackPanel>  
 
                     <Border Style="{StaticResource headerBanner}">  
                         <TextBlock Style="{StaticResource headerText}"  
                                    Text="Result" />  
                     </Border>  
                     <Grid Margin="0 0 0 10">  
                         <Grid.ColumnDefinitions>  
                             <ColumnDefinition Width="auto" />  
                             <ColumnDefinition Width="*" />  
                         </Grid.ColumnDefinitions>  
                         <StackPanel Grid.Row="0"  
                                     Grid.Column="0"  
                                     Margin="5 0 0 0"  
                                     VerticalAlignment="Center"  
                                     Orientation="Horizontal">  
                             <RadioButton x:Name="rbtnShortest"  
                                          Command="{Binding CalculateDirectionCommand}"  
                                          CommandParameter="Shortest"  
                                          GroupName="rbtnRouteMode">  
                                 Shortest  
                             </RadioButton>  
                             <RadioButton x:Name="rbtnFastest"  
                                          Margin="5 0 0 0"  
                                          Command="{Binding CalculateDirectionCommand}"  
                                          CommandParameter="Fastest"  
                                          GroupName="rbtnRouteMode"  
                                          IsChecked="True">  
                                 Fastest  
                             </RadioButton>  
                         </StackPanel>  
                         <ComboBox x:Name="cblDistanceUnt"  
                                   Grid.Row="0"  
                                   Grid.Column="1"  
                                   Margin="15 0 0 0"  
                                   SelectedItem="{Binding DistanceUnit,Mode=TwoWay}"  
                                   ItemsSource="{Binding DistanceUnitCandidates}" >  
                             <ComboBox.ItemTemplate>  
                                 <DataTemplate>  
                                     <TextBlock Text="{Binding .,Converter={StaticResource DistanceUnitToStringConverter}}" />  
                                 </DataTemplate>  
                             </ComboBox.ItemTemplate>  
                         </ComboBox>  
                     </Grid>  
                 </StackPanel>  
                 <DataGrid Grid.Row="1"  
                           Width="300"  
                           Margin="0 0 0 5"  
                           AutoGenerateColumns="False"  
                           CanUserSortColumns="False"  
                           ItemsSource="{Binding DirectionResultList}">  
                     <DataGrid.Resources>  
                         <local:DirectionTypeToImageSourceConverter x:Key="DirectionTypeToImageSourceConverter" />  
                     </DataGrid.Resources>  
                     <DataGrid.Columns>  
                         <DataGridTemplateColumn CanUserResize="False">  
                             <DataGridTemplateColumn.CellTemplate>  
                                 <DataTemplate>  
                                     <Image Width="20"  
                                            Height="20"  
                                            Source="{Binding Direction, Converter={StaticResource DirectionTypeToImageSourceConverter}}" />  
                                 </DataTemplate>  
                             </DataGridTemplateColumn.CellTemplate>  
                         </DataGridTemplateColumn>  
                         <DataGridTextColumn Width="160"  
                                             Binding="{Binding RoadName}"  
                                             Header="Road Name"  
                                             IsReadOnly="True" />  
                         <DataGridTextColumn Width="*"  
                                             Binding="{Binding Length}"  
                                             Header="Length"  
                                             IsReadOnly="True" />  
                     </DataGrid.Columns>  
                 </DataGrid>  
             </Grid>  
             <StackPanel Grid.Column="1" Orientation="Horizontal">  
                 <ToggleButton x:Name="btnCollpaseToggle"  
                               VerticalAlignment="Center"  
                               Background="Transparent"  
                               BorderBrush="Transparent"  
                               Cursor="Hand">  
                     <ToggleButton.Style>  
                         <Style>  
                             <Style.Triggers>  
                                 <Trigger Property="ToggleButton.IsChecked" Value="False">  
                                     <Setter Property="ToggleButton.Content">  
                                         <Setter.Value>  
                                             <Image Source="/CityRoutingAndDirections;Component/Image/collapse.gif" Stretch="None" />  
                                         </Setter.Value>  
                                     </Setter>  
                                 </Trigger>  
                                 <Trigger Property="ToggleButton.IsChecked" Value="True">  
                                     <Setter Property="ToggleButton.Content">  
                                         <Setter.Value>  
                                             <Image Source="/CityRoutingAndDirections;Component/Image/expand.gif" Stretch="None" />  
                                         </Setter.Value>  
                                     </Setter>  
                                 </Trigger>  
                             </Style.Triggers>  
                         </Style>  
                     </ToggleButton.Style>  
                 </ToggleButton>  
                 <Rectangle Width="5">  
                     <Rectangle.Fill>  
                         <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">  
                             <GradientStop Offset="0" Color="#5c707d" />  
                             <GradientStop Offset="1" Color="#305c707d" />  
                         </LinearGradientBrush>  
                     </Rectangle.Fill>  
                 </Rectangle>  
             </StackPanel>  
             <wpf:WpfMap x:Name="wpfMap1"  
                         Grid.Column="2"  
                         Panel.ZIndex="-1">  
                 <wpf:WpfMap.ContextMenu>  
                     <ContextMenu x:Name="menuRoute">  
                         <MenuItem x:Name="menuiStart"  
                                   Command="{Binding AddPointCommand}"  
                                   CommandParameter="Start">  
                             <MenuItem.Header>  
                                 <TextBlock VerticalAlignment="Center" Text="Directions from here" />  
                             </MenuItem.Header>  
                             <MenuItem.Icon>  
                                 <Image Height="20" Source="/CityRoutingAndDirections;component/Image/start.png" />  
                             </MenuItem.Icon>  
                         </MenuItem>  
                         <MenuItem x:Name="menuiEnd"  
                                   Command="{Binding AddPointCommand}"  
                                   CommandParameter="End">  
                             <MenuItem.Header>  
                                 <TextBlock VerticalAlignment="Center" Text="Directions to here" />  
                             </MenuItem.Header>  
                             <MenuItem.Icon>  
                                 <Image Height="20" Source="/CityRoutingAndDirections;component/Image/end.png" />  
                             </MenuItem.Icon>  
                         </MenuItem>  
                         <MenuItem x:Name="menuiStop"  
                                   Command="{Binding AddPointCommand}"  
                                   CommandParameter="Stop">  
                             <MenuItem.Header>  
                                 <TextBlock VerticalAlignment="Center" Text="Add a waypoint here" />  
                             </MenuItem.Header>  
                             <MenuItem.Icon>  
                                 <Image Height="20" Source="/CityRoutingAndDirections;component/Image/stop.png" />  
                             </MenuItem.Icon>  
                         </MenuItem>  
                     </ContextMenu>  
                 </wpf:WpfMap.ContextMenu>  
             </wpf:WpfMap>  
             <local:LoadingImageUserControl Grid.Column="2" Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibilityConverter}}" />  
         </Grid>  
         <Grid Grid.Row="2">  
             <Border BorderBrush="Gray" BorderThickness="0 1 0 0">  
                 <StatusBar Height="30">  
                     <StatusBarItem HorizontalContentAlignment="Stretch">  
                         <Grid HorizontalAlignment="Right">  
                             <Grid.ColumnDefinitions>  
                                 <ColumnDefinition Width="auto" />  
                                 <ColumnDefinition Width="5" />  
                                 <ColumnDefinition Width="auto" />  
                             </Grid.ColumnDefinitions>  
                             <TextBlock x:Name="tblCoordinateX"  
                                        Grid.Column="0"  
                                        Width="75"  
                                        HorizontalAlignment="Right"  
                                        VerticalAlignment="Center"  
                                        Text="{Binding CoordinateX, StringFormat=X: {0:N6}}" />  
                             <TextBlock x:Name="tblCoordinateY"  
                                        Grid.Column="2"  
                                        Width="75"  
                                        VerticalAlignment="Center"  
                                        Text="{Binding CoordinateY, StringFormat=Y: {0:N6}}" />  
                         </Grid>  
                     </StatusBarItem>  
                 </StatusBar>  
             </Border>  
         </Grid>  
     </Grid>  
 </Window>  
 
 

BooleanToReverseVisibilityConverter.cs

 using System;  
 using System.Globalization;  
 using System.Windows;  
 using System.Windows.Data;  
 
 namespace ThinkGeo.MapSuite.RoutingExamples  
 {  
     public class BooleanToReverseVisibilityConverter :IValueConverter  
     {  
         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)  
         {  
             if (value is bool)  
             {  
                 bool isVisible = (bool)value;  
                 return isVisible ? Visibility.Collapsed : Visibility.Visible;  
             }  
 
             return Binding.DoNothing;  
         }  
 
         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)  
         {  
             return Binding.DoNothing;  
         }  
     }  
 }  
 
 

RouteDirectionModel.cs

 using System;  
 using System.Globalization;  
 using ThinkGeo.MapSuite.Core;  
 using ThinkGeo.MapSuite.Routing;  
 
 namespace ThinkGeo.MapSuite.RoutingExamples  
 {  
     public class RouteDirectionViewModel : ViewModelBase  
     {  
         private string roadNameColumnName;  
         private Feature roadFeature;  
         private DistanceUnit lengthUnit;  
         private RouteSegment roadSegment;  
         private GeographyUnit geographyUnit;  
 
         public RouteDirectionViewModel()  
             : this(null, null, null)  
         { }  
 
         public RouteDirectionViewModel(RouteSegment roadSegment, Feature roadFeature, string roadNameColumnName)  
             : this(roadSegment, roadFeature, roadNameColumnName, GeographyUnit.DecimalDegree, DistanceUnit.Meter)  
         { }  
 
         public RouteDirectionViewModel(RouteSegment roadSegment, Feature roadFeature, string roadNameColumnName, GeographyUnit geographyUnit, DistanceUnit lengthUnit)  
         {  
             this.lengthUnit = lengthUnit;  
             this.roadSegment = roadSegment;  
             this.roadFeature = roadFeature;  
             this.geographyUnit = geographyUnit;  
             this.roadNameColumnName = roadNameColumnName;  
         }  
 
         public DrivingDirection Direction  
         {  
             get  
             {  
                 return roadSegment != null ? roadSegment.DrivingDirection : DrivingDirection.Back;  
             }  
         }  
 
         public GeographyUnit GeographyUnit  
         {  
             get { return geographyUnit; }  
             set { geographyUnit = value; }  
         }  
 
         public string Length  
         {  
             get  
             {  
                 string length = string.Empty;  
 
                 if (RoadFeature != null)  
                 {  
                     double value = Math.Round(((LineBaseShape)RoadFeature.GetShape()).GetLength(GeographyUnit, lengthUnit), 2);  
                     length = String.Format(CultureInfo.InvariantCulture, "{0} {1}", value, lengthUnit == DistanceUnit.Mile ? "mi" : "km");  
                 }  
 
                 return length;  
             }  
         }  
 
         public DistanceUnit LengthUnit  
         {  
             get { return lengthUnit; }  
             set  
             {  
                 lengthUnit = value;  
                 RaisePropertyChanged(() => LengthUnit);  
                 RaisePropertyChanged(() => Length);  
             }  
         }  
 
         public Feature RoadFeature  
         {  
             get { return roadFeature; }  
             set { roadFeature = value; }  
         }  
 
         public string RoadName  
         {  
             get  
             {  
                 return !string.IsNullOrEmpty(RoadNameColumnName) ? roadFeature.ColumnValues[RoadNameColumnName] : string.Empty;  
             }  
         }  
 
         public string RoadNameColumnName  
         {  
             get { return roadNameColumnName; }  
             set { roadNameColumnName = value; }  
         }  
     }  
 }  
 

CommandBase.cs

 using System;  
 using System.Diagnostics;  
 using System.Windows.Input;  
 
 namespace ThinkGeo.MapSuite.RoutingExamples  
 {  
     public class CommandBase : ICommand  
     {  
         private readonly Predicate<object> _canExecute;  
         private readonly Action<object> _execute;  
 
         public CommandBase(Action<object> execute)  
 
             : this(execute, null)  
         {  
         }  
 
         public CommandBase(Action<object> execute, Predicate<object> canExecute)  
         {  
             if (execute == null)  
 
                 throw new ArgumentNullException("execute");  
 
             _execute = execute;  
 
             _canExecute = canExecute;  
         }  
 
         public event EventHandler CanExecuteChanged  
         {  
             add { CommandManager.RequerySuggested += value; }  
 
             remove { CommandManager.RequerySuggested -= value; }  
         }  
 
         [DebuggerStepThrough]  
         public bool CanExecute(object parameter)  
         {  
             return _canExecute == null ? true : _canExecute(parameter);  
         }  
 
         public void Execute(object parameter)  
         {  
             _execute(parameter);  
         }  
     }  
 }  
 

JsonSerializer.cs

 using System;  
 using System.Windows;  
 using System.Windows.Data;  
 
 namespace ThinkGeo.MapSuite.RoutingExamples  
 {  
     public class CountToVisibilityConverter : IValueConverter  
     {  
         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
         {  
             Visibility result = Visibility.Visible;  
             int count = (int)value;  
             if (count > 0) result = Visibility.Hidden;  
 
             return result;  
         }  
 
         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
         {  
             return Binding.DoNothing;  
         }  
     }  
 }  
 

DirectionTypeToImageSourceConverter.cs

 using System;  
 using System.Globalization;  
 using System.Windows.Data;  
 using System.Windows.Media.Imaging;  
 using ThinkGeo.MapSuite.Routing;  
 
 namespace ThinkGeo.MapSuite.RoutingExamples  
 {  
     public class DirectionTypeToImageSourceConverter : IValueConverter  
     {  
         private static string directionImageUriTemplate = "/CityRoutingAndDirections;component/Image/Directions/{0}";  
 
         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
         {  
             if (value is DrivingDirection)  
             {  
                 DrivingDirection direction = (DrivingDirection)value;  
                 string directionImageUriString;  
                 switch (direction)  
                 {  
                     case DrivingDirection.Back:  
                         directionImageUriString = "back.png";  
                         break;  
 
                     case DrivingDirection.Forward:  
                         directionImageUriString = "Forward.png";  
                         break;  
 
                     case DrivingDirection.Invalid:  
                         directionImageUriString = "Invalid.png";  
                         break;  
 
                     case DrivingDirection.LeftForward:  
                         directionImageUriString = "LeftForward.png";  
                         break;  
 
                     case DrivingDirection.RightBack:  
                         directionImageUriString = "RightBack.png";  
                         break;  
 
                     case DrivingDirection.RightForward:  
                         directionImageUriString = "RightForward.png";  
                         break;  
 
                     case DrivingDirection.LeftBack:  
                         directionImageUriString = "LeftBack.png";  
                         break;  
 
                     case DrivingDirection.Left:  
                         directionImageUriString = "Left.png";  
                         break;  
 
                     default:  
                         directionImageUriString = "Right.png";  
                         break;  
                 }  
 
                 string url = string.Format(CultureInfo.InvariantCulture, directionImageUriTemplate, directionImageUriString);  
                 return new BitmapImage(new Uri(url, UriKind.RelativeOrAbsolute));  
             }  
 
             return Binding.DoNothing;  
         }  
 
         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)  
         {  
             return Binding.DoNothing;  
         }  
     }  
 }  
 

PointShapeToStringConverter.cs

 using System;  
 using System.Globalization;  
 using System.Windows.Data;  
 using ThinkGeo.MapSuite.Core;  
 
 namespace ThinkGeo.MapSuite.RoutingExamples  
 {  
     public class PointShapeToStringConverter : IValueConverter  
     {  
         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)  
         {  
             object returnValue = string.Empty;  
             PointShape point = value as PointShape;  
             if (point != null)  
             {  
                 returnValue = string.Format(CultureInfo.InvariantCulture, "{0}, {1}", point.X.ToString("N8"), point.Y.ToString("N8"));  
             }  
 
             return returnValue;  
         }  
 
         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)  
         {  
             object returnValue = null;  
             string pointText = value as string;  
             if (!string.IsNullOrEmpty(pointText))  
             {  
                 if (pointText != null)  
                 {  
                     string[] segements = pointText.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);  
                     double x, y;  
                     if (segements.Length == 2 && double.TryParse(segements[0], out x) &&  
                         double.TryParse(segements[1], out y))  
                     {  
                         returnValue = new PointShape(x, y);  
                     }  
                 }  
             }  
 
             return returnValue;  
         }  
     }  
 }  
 

MainWindowViewModel.cs

 using System;  
 using System.Collections.ObjectModel;  
 using System.Collections.Specialized;  
 using System.ComponentModel;  
 using System.Globalization;  
 using System.IO;  
 using System.Linq;  
 using System.Threading.Tasks;  
 using System.Windows;  
 using System.Windows.Media.Imaging;  
 using ThinkGeo.MapSuite.Core;  
 using ThinkGeo.MapSuite.Routing;  
 using ThinkGeo.MapSuite.WpfDesktopEdition;  
 
 namespace ThinkGeo.MapSuite.RoutingExamples  
 {  
     public class MainWindowViewModel : ViewModelBase  
     {  
         private static readonly string roadColumnName = "FULL_STREE";  
         private static readonly string austinCountyShapeFile = @"..\..\App_Data\AustinBorder.shp";  
         private static readonly string austinStreetShapeFile = @"..\..\App_Data\austin_streets.shp";  
         private static readonly string rtgFastestFile = @"..\..\App_Data\austin_streets_fastest.rtg";  
         private static readonly string rtgShortestFile = @"..\..\App_Data\austin_streets_shortest.rtg";  
         private static readonly RectangleShape defaultExtent = new RectangleShape(-97.803553154785, 30.352039937378, -97.700175654785, 30.259261310914);  
 
         private bool isBusy;  
         private double coordinateX;  
         private double coordinateY;  
         private MultipolygonShape restrictedPolygon;  
         private WpfMap mapControl;  
         private DistanceUnit distanceUnit;  
         private RoutingLayer routingLayer;  
         private RoutePriority routePriority;  
         private LayerOverlay routingOverlay;  
         private PointShape routeLocationPoint;  
         private InMemoryFeatureLayer barrierLayer;  
         private ShapeFileFeatureLayer restrictedLayer;  
         private ShapeFileFeatureLayer routingShapeFile;  
         private Collection<string> avoidableFeatureIds;  
         private Collection<DistanceUnit> distanceUnitCandidates;  
         private ObservableCollection<StopItemViewModel> stopItems;  
         private ObservableCollection<RouteDirectionViewModel> directionResultList;  
 
         private CommandBase undoCommand;  
         private CommandBase clearAllCommand;  
         private CommandBase addPointCommand;  
         private CommandBase deleteStopCommand;  
         private CommandBase clearBarriersCommand;  
         private CommandBase updateTrackModeCommand;  
         private CommandBase calculateDirectionCommand;  
         private CommandBase inverseDestinationCommand;  
 
         public MainWindowViewModel(WpfMap map)  
         {  
             mapControl = map;  
             distanceUnit = DistanceUnit.Mile;  
 
             PointShape defaultCenter = defaultExtent.GetCenterPoint();  
             coordinateX = defaultCenter.X;  
             coordinateY = defaultCenter.Y;  
 
             avoidableFeatureIds = new Collection<string>();  
             stopItems = new ObservableCollection<StopItemViewModel>();  
             stopItems.CollectionChanged += LocationItems_CollectionChanged;  
 
             InitializeMap();  
         }  
 
         public DistanceUnit DistanceUnit  
         {  
             get { return distanceUnit; }  
             set  
             {  
                 distanceUnit = value;  
                 RaisePropertyChanged(() => DistanceUnit);  
 
                 if (mapControl != null)  
                 {  
                     ScaleBarAdornmentLayer adornmentLayer = (ScaleBarAdornmentLayer)mapControl.AdornmentOverlay.Layers["ScaleBar"];  
                     adornmentLayer.UnitFamily = value == DistanceUnit.Kilometer ? UnitSystem.Metric : UnitSystem.Imperial;  
                 }  
 
                 foreach (RouteDirectionViewModel item in DirectionResultList)  
                 {  
                     item.LengthUnit = distanceUnit;  
                 }  
             }  
         }  
 
         public Collection<DistanceUnit> DistanceUnitCandidates  
         {  
             get { return distanceUnitCandidates ?? (distanceUnitCandidates = new Collection<DistanceUnit> { DistanceUnit.Mile, DistanceUnit.Kilometer }); }  
         }  
 
         public bool IsBusy  
         {  
             get { return isBusy; }  
             set  
             {  
                 isBusy = value;  
                 RaisePropertyChanged(() => IsBusy);  
             }  
         }  
 
         public WpfMap MapControl  
         {  
             get { return mapControl; }  
             set { mapControl = value; }  
         }  
 
         public double CoordinateX  
         {  
             get { return coordinateX; }  
             set  
             {  
                 coordinateX = value;  
                 RaisePropertyChanged(() => CoordinateX);  
             }  
         }  
 
         public double CoordinateY  
         {  
             get { return coordinateY; }  
             set  
             {  
                 coordinateY = value;  
                 RaisePropertyChanged(() => CoordinateY);  
             }  
         }  
 
         public PointShape StartPoint  
         {  
             get { return routingLayer.StartPoint; }  
             set  
             {  
                 if (routingLayer.StartPoint != value)  
                 {  
                     routingLayer.StartPoint = value;  
                     RaisePropertyChanged(() => StartPoint);  
 
                     routingOverlay.Refresh();  
                 }  
             }  
         }  
 
         public PointShape EndPoint  
         {  
             get { return routingLayer.EndPoint; }  
             set  
             {  
                 if (routingLayer.EndPoint != value)  
                 {  
                     routingLayer.EndPoint = value;  
                     RaisePropertyChanged(() => EndPoint);  
 
                     routingOverlay.Refresh();  
                 }  
             }  
         }  
 
         public ObservableCollection<RouteDirectionViewModel> DirectionResultList  
         {  
             get  
             {  
                 return directionResultList ?? (directionResultList = new ObservableCollection<RouteDirectionViewModel>());  
             }  
         }  
 
         public ObservableCollection<StopItemViewModel> StopItems  
         {  
             get { return stopItems; }  
         }  
 
         public CommandBase UndoCommand  
         {  
             get  
             {  
                 return undoCommand ?? (undoCommand = new CommandBase(obj =>  
                 {  
                     if (barrierLayer.InternalFeatures.Count == 0) return;  
 
                     barrierLayer.InternalFeatures.RemoveAt(barrierLayer.InternalFeatures.Count - 1);  
                     routingShapeFile.Open();  
                     avoidableFeatureIds.Clear();  
                     foreach (Feature feature in barrierLayer.InternalFeatures)  
                     {  
                         Collection<Feature> features = routingShapeFile.FeatureSource.GetFeaturesWithinDistanceOf(feature, mapControl.MapUnit, DistanceUnit.Meter, 1, ReturningColumnsType.NoColumns);  
                         foreach (Feature avoidableFeature in features)  
                         {  
                             avoidableFeatureIds.Add(avoidableFeature.Id);  
                         }  
                     }  
 
                     routingOverlay.Refresh();  
                 }));  
             }  
         }  
 
         public CommandBase AddPointCommand  
         {  
             get  
             {  
                 return addPointCommand ?? (addPointCommand = new CommandBase(obj =>  
                 {  
                     restrictedLayer.Open();  
                     Collection<Feature> features = restrictedLayer.FeatureSource.GetAllFeatures(ReturningColumnsType.NoColumns);  
                     if (features.Count > 0 && !features[0].GetShape().Contains(routeLocationPoint))  
                     {  
                         Window warningWindow = new CityRoutingWarningWindow();  
                         warningWindow.Owner = Application.Current.MainWindow;  
                         warningWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;  
                         warningWindow.ShowDialog();  
                         return;  
                     }  
 
                     string commandParameter = obj as string;  
                     if (commandParameter != null)  
                     {  
                         switch (commandParameter)  
                         {  
                             case "Start":  
                                 StartPoint = routeLocationPoint;  
                                 break;  
 
                             case "End":  
                                 EndPoint = routeLocationPoint;  
                                 break;  
 
                             case "Stop":  
                                 routingLayer.StopPoints.Add(routeLocationPoint);  
                                 StopItemViewModel locationItem = new StopItemViewModel(routeLocationPoint);  
                                 locationItem.PropertyChanged += SyncStopsToRouteLayer;  
                                 StopItems.Add(locationItem);  
                                 break;  
                         }  
 
                         DirectionResultList.Clear();  
                         routingLayer.Routes.Clear();  
                     }  
 
                     routingOverlay.Refresh();  
                 }));  
             }  
         }  
 
         public CommandBase ClearAllCommand  
         {  
             get  
             {  
                 return clearAllCommand ?? (clearAllCommand = new CommandBase(obj =>  
                 {  
                     EndPoint = null;  
                     StartPoint = null;  
                     StopItems.Clear();  
                     DirectionResultList.Clear();  
                     routingLayer.StopPoints.Clear();  
                     routingLayer.Routes.Clear();  
                     routingOverlay.Refresh();  
                 }));  
             }  
         }  
 
         public CommandBase DeleteStopCommand  
         {  
             get  
             {  
                 return deleteStopCommand ?? (deleteStopCommand = new CommandBase(obj =>  
                 {  
                     StopItemViewModel item = (StopItemViewModel)obj;  
                     StopItems.Remove(item);  
                     routingLayer.StopPoints.Remove(item.Location);  
                     routingLayer.Routes.Clear();  
                     DirectionResultList.Clear();  
                     routingOverlay.Refresh();  
                 }));  
             }  
         }  
 
         public CommandBase ClearBarriersCommand  
         {  
             get  
             {  
                 return clearBarriersCommand ?? (clearBarriersCommand = new CommandBase(obj =>  
                 {  
                     barrierLayer.InternalFeatures.Clear();  
                     avoidableFeatureIds.Clear();  
                     routingOverlay.Refresh();  
                 }));  
             }  
         }  
 
         public CommandBase UpdateTrackModeCommand  
         {  
             get  
             {  
                 return updateTrackModeCommand ?? (updateTrackModeCommand = new CommandBase(obj =>  
                 {  
                     string commandParameter = obj as string;  
                     if (!string.IsNullOrEmpty(commandParameter))  
                     {  
                         mapControl.TrackOverlay.TrackMode = (TrackMode)Enum.Parse(typeof(TrackMode), commandParameter);  
                     }  
                 }));  
             }  
         }  
 
         public CommandBase CalculateDirectionCommand  
         {  
             get  
             {  
                 return calculateDirectionCommand ?? (calculateDirectionCommand = new CommandBase(obj =>  
                 {  
                     if (routingLayer == null || routingLayer.StartPoint == null || routingLayer.EndPoint == null) return;  
 
                     IsBusy = true;  
                     string commandParameter = obj as string;  
                     if (!string.IsNullOrEmpty(commandParameter))  
                     {  
                         routePriority = (RoutePriority)Enum.Parse(typeof(RoutePriority), commandParameter);  
                     }  
 
                     string rtgFilePathName = string.Empty;  
                     switch (routePriority)  
                     {  
                         case RoutePriority.Fastest:  
                             rtgFilePathName = rtgFastestFile;  
                             break;  
 
                         case RoutePriority.Shortest:  
                             rtgFilePathName = rtgShortestFile;  
                             break;  
                     }  
 
                     Task.Factory.StartNew(() =>  
                     {  
                         RtgRoutingSource routingSource = new RtgRoutingSource(rtgFilePathName);  
                         RoutingEngine routingEngine = new RoutingEngine(routingSource, routingShapeFile.FeatureSource);  
 
                         RoutePathAndDirection routePathAndDirection = new RoutePathAndDirection(routingEngine, routingLayer.StartPoint, routingLayer.EndPoint, barrierLayer.FeatureSource, avoidableFeatureIds, routingLayer.StopPoints);  
                         RoutingResult result = routePathAndDirection.GetRoute();  
 
                         routingLayer.Routes.Clear();  
                         routingLayer.Routes.Add(result.Route);  
 
                         Application.Current.Dispatcher.BeginInvoke(new Action(() =>  
                         {  
                             DirectionResultList.Clear();  
                             for (int i = 0; i < result.RouteSegments.Count; i++)  
                             {  
                                 RouteDirectionViewModel routeDirection = new RouteDirectionViewModel(result.RouteSegments[i], result.Features[i], roadColumnName, mapControl.MapUnit, distanceUnit);  
                                 DirectionResultList.Add(routeDirection);  
                             }  
 
                             routingOverlay.Refresh();  
                             IsBusy = false;  
                         }));  
                     });  
                 }));  
             }  
         }  
 
         public CommandBase InverseDestinationCommand  
         {  
             get  
             {  
                 return inverseDestinationCommand ?? (inverseDestinationCommand = new CommandBase(obj =>  
                 {  
                     PointShape end = StartPoint;  
                     StartPoint = EndPoint;  
                     EndPoint = end;  
                     routingOverlay.Refresh();  
                 }));  
             }  
         }  
 
         private void InitializeMap()  
         {  
             routingShapeFile = new ShapeFileFeatureLayer(austinStreetShapeFile);  
 
             mapControl.MapUnit = GeographyUnit.DecimalDegree;  
             mapControl.CurrentExtent = defaultExtent;  
             mapControl.MapTools.MouseCoordinate.IsEnabled = true;  
             mapControl.MapTools.MouseCoordinate.MouseCoordinateType = MouseCoordinateType.Custom;  
             mapControl.MapTools.MouseCoordinate.CustomFormatted += MouseCoordinate_CustomFormatted;  
             mapControl.MapTools.PanZoomBar.GlobeButtonClick += (s, e) => e.NewExtent = defaultExtent;  
             mapControl.TrackOverlay.TrackEnded += TrackOverlay_TrackEnded;  
             mapControl.PreviewMouseRightButtonDown += MapControl_PreviewMouseRightButtonDown;  
 
             //Init Backgound Layer  
             mapControl.Overlays.Add("WorldMapKit", new WorldMapKitWmsWpfOverlay());  
 
             //Init RoutingOverlay  
             routingOverlay = new LayerOverlay();  
             mapControl.Overlays.Add("RoutingOverlay", routingOverlay);  
 
             routingLayer = new RoutingLayer();  
             routingLayer.StartPointStyle = new PointStyle(GetMarkerImage("start"));  
             routingLayer.EndPointStyle = new PointStyle(GetMarkerImage("end"));  
             routingLayer.StopPointStyle = new PointStyle(GetMarkerImage("stop"));  
             routingLayer.StopPointStyle.YOffsetInPixel = -10;  
             routingLayer.StopTextStyle.TextSolidBrush.Color = GeoColor.StandardColors.White;  
             routingLayer.StopTextStyle.Font = new GeoFont("Arial", 10);  
             routingLayer.XOffsetInPixelOfStopOrder = -3;  
             routingLayer.YOffsetInPixelOfStopOrder = 14;  
             routingOverlay.Layers.Add("RoutingLayer", routingLayer);  
 
             barrierLayer = new InMemoryFeatureLayer();  
             barrierLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(GeoColor.FromArgb(100, GeoColor.SimpleColors.Red), GeoColor.SimpleColors.Red, 1);  
             barrierLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
             routingOverlay.Layers.Add("BarrierLayer", barrierLayer);  
 
             //Init restrictedOverlay  
             LayerOverlay restrictedOverlay = new LayerOverlay();  
             mapControl.Overlays.Add("RestrictedOverlay", restrictedOverlay);  
 
             restrictedLayer = new ShapeFileFeatureLayer(austinCountyShapeFile);  
             restrictedLayer.Open();  
             restrictedPolygon = (MultipolygonShape)restrictedLayer.QueryTools.GetAllFeatures(ReturningColumnsType.AllColumns)[0].GetShape();  
             AreaStyle extentStyle = new AreaStyle();  
             extentStyle.CustomAreaStyles.Add(new AreaStyle(new GeoSolidBrush(GeoColor.SimpleColors.Transparent)) { OutlinePen = new GeoPen(GeoColor.SimpleColors.White, 9.5f) });  
             extentStyle.CustomAreaStyles.Add(new AreaStyle(new GeoSolidBrush(GeoColor.SimpleColors.Transparent)) { OutlinePen = new GeoPen(GeoColor.SimpleColors.Red, 1.5f) { DashStyle = LineDashStyle.Dash } });  
             restrictedLayer.ZoomLevelSet.ZoomLevel01.DefaultAreaStyle = extentStyle;  
             restrictedLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;  
             restrictedOverlay.Layers.Add("RestrictedLayer", restrictedLayer);  
 
             // Scale bar layer  
             ScaleBarAdornmentLayer scaleBarAdormentLayer = new ScaleBarAdornmentLayer();  
             scaleBarAdormentLayer.Location = AdornmentLocation.LowerLeft;  
             scaleBarAdormentLayer.XOffsetInPixel = 10;  
             mapControl.AdornmentOverlay.Layers.Add("ScaleBar", scaleBarAdormentLayer);  
 
             mapControl.Refresh();  
         }  
 
         private void SyncStopsToRouteLayer(object sender, PropertyChangedEventArgs e)  
         {  
             if (e.PropertyName.Equals("Location"))  
             {  
                 routingLayer.StopPoints.Clear();  
                 foreach (var item in StopItems)  
                 {  
                     routingLayer.StopPoints.Add(item.Location);  
                 }  
             }  
         }  
 
         private void LocationItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)  
         {  
             for (int i = 0; i < stopItems.Count; i++)  
             {  
                 StopItems[i].MarkerImageSource = GetMarkerImageSource(i + 1);  
             }  
         }  
 
         private void MouseCoordinate_CustomFormatted(object sender, CustomFormattedMouseCoordinateMapToolEventArgs e)  
         {  
             CoordinateX = e.WorldCoordinate.X;  
             CoordinateY = e.WorldCoordinate.Y;  
         }  
 
         private void TrackOverlay_TrackEnded(object sender, TrackEndedTrackInteractiveOverlayEventArgs e)  
         {  
             if (mapControl.TrackOverlay.TrackShapeLayer.InternalFeatures.Count > 0)  
             {  
                 PolygonShape trackedPolygonShape = mapControl.TrackOverlay.TrackShapeLayer.InternalFeatures[0].GetShape() as PolygonShape;  
                 if (trackedPolygonShape != null && trackedPolygonShape.IsWithin(restrictedPolygon))  
                 {  
                     barrierLayer.InternalFeatures.Add(mapControl.TrackOverlay.TrackShapeLayer.InternalFeatures[0]);  
                 }  
                 else  
                 {  
                     MessageBox.Show("Please note that this sample map is only able to analyze service areas within the Austin city limits, which are indicated by a dashed red line. Click inside that boundary for best results.", "Draw Area");  
                 }  
                 mapControl.TrackOverlay.TrackShapeLayer.InternalFeatures.Clear();  
             }  
 
             routingShapeFile.Open();  
             avoidableFeatureIds.Clear();  
             foreach (Feature feature in barrierLayer.InternalFeatures)  
             {  
                 Collection<Feature> features = routingShapeFile.FeatureSource.GetFeaturesWithinDistanceOf(feature, mapControl.MapUnit, DistanceUnit.Meter, 1, ReturningColumnsType.NoColumns);  
                 foreach (Feature avoidableFeature in features.Where(f => !avoidableFeatureIds.Contains(f.Id)))  
                 {  
                     avoidableFeatureIds.Add(avoidableFeature.Id);  
                 }  
             }  
 
             routingOverlay.Refresh();  
         }  
 
         private void MapControl_PreviewMouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)  
         {  
             Point menuRouteMouseLocation = e.GetPosition(mapControl);  
             ScreenPointF mouseScreenPoint = new ScreenPointF((float)menuRouteMouseLocation.X, (float)menuRouteMouseLocation.Y);  
             routeLocationPoint = ExtentHelper.ToWorldCoordinate(mapControl.CurrentExtent, mouseScreenPoint, (float)mapControl.ActualWidth, (float)mapControl.ActualHeight);  
         }  
 
         private static GeoImage GetMarkerImage(string imageName)  
         {  
             string url = string.Format(CultureInfo.InvariantCulture, "pack://application:,,,/CityRoutingAndDirections;Component/Image/{0}.png", imageName);  
             return new GeoImage(Application.GetResourceStream(new Uri(url, UriKind.RelativeOrAbsolute)).Stream);  
         }  
 
         private static BitmapImage GetMarkerImageSource(int index)  
         {  
             System.Drawing.Bitmap bitmap = null;  
             System.Drawing.Graphics g = null;  
 
             try  
             {  
                 Uri stopImageUri = new Uri("pack://application:,,,/CityRoutingAndDirections;Component/Image/stop.png", UriKind.RelativeOrAbsolute);  
                 bitmap = new System.Drawing.Bitmap(Application.GetResourceStream(stopImageUri).Stream);  
                 g = System.Drawing.Graphics.FromImage(bitmap);  
 
                 string currentIndex = index.ToString(CultureInfo.InvariantCulture);  
                 System.Drawing.Font font = new System.Drawing.Font("Segoe UI", 10, System.Drawing.FontStyle.Bold);  
                 System.Drawing.SizeF size = g.MeasureString(currentIndex, font);  
                 g.DrawString(currentIndex, font, new System.Drawing.SolidBrush(System.Drawing.Color.White), new System.Drawing.PointF((bitmap.Width - size.Width) / 2, 0));  
 
                 MemoryStream ms = new MemoryStream();  
                 bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);  
                 byte[] bytes = ms.GetBuffer();  
 
                 BitmapImage bitmapImage = new BitmapImage();  
                 bitmapImage.BeginInit();  
                 bitmapImage.StreamSource = new MemoryStream(bytes);  
                 bitmapImage.EndInit();  
                 return bitmapImage;  
             }  
             finally  
             {  
                 if (bitmap != null) bitmap.Dispose();  
                 if (g != null) g.Dispose();  
             }  
         }  
 
         private enum RoutePriority  
         {  
             Shortest = 0,  
             Fastest = 1  
         }  
     }  
 }  
 

RoutePathAndDirection.cs

 using System.Collections.Generic;  
 using System.Collections.ObjectModel;  
 using System.Linq;  
 using ThinkGeo.MapSuite.Core;  
 using ThinkGeo.MapSuite.Routing;  
 
 namespace ThinkGeo.MapSuite.RoutingExamples  
 {  
     public class RoutePathAndDirection  
     {  
         private readonly List<PointShape> stopPoints;  
         private readonly List<string> avoidableFeatureIds;  
 
         private PointShape endPoint;  
         private PointShape startPoint;  
         private RoutingEngine routingEngine;  
         private FeatureSource barrierFeatureSource;  
 
         public RoutePathAndDirection()  
         { }  
 
         public RoutePathAndDirection(RoutingEngine routingEngine, PointShape startPoint, PointShape endPoint)  
             : this(routingEngine, startPoint, endPoint, null)  
         { }  
 
         public RoutePathAndDirection(RoutingEngine routingEngine, PointShape startPoint, PointShape endPoint, FeatureSource barrierFeatureSource)  
             : this(routingEngine, startPoint, endPoint, barrierFeatureSource, new string[] { })  
         { }  
 
         public RoutePathAndDirection(RoutingEngine routingEngine, PointShape startPoint, PointShape endPoint, FeatureSource barrierFeatureSource, IEnumerable<string> avoidableFeatureIds)  
             : this(routingEngine, startPoint, endPoint, barrierFeatureSource, avoidableFeatureIds, new PointShape[] { })  
         { }  
 
         public RoutePathAndDirection(RoutingEngine routingEngine, PointShape startPoint, PointShape endPoint, FeatureSource barrierFeatureSource, IEnumerable<PointShape> stopPoints)  
             : this(routingEngine, startPoint, endPoint, barrierFeatureSource, new string[] { }, stopPoints)  
         { }  
 
         public RoutePathAndDirection(RoutingEngine routingEngine, PointShape startPoint, PointShape endPoint, FeatureSource barrierFeatureSource, IEnumerable<string> avoidableFeatureIds, IEnumerable<PointShape> stopPoints)  
         {  
             this.endPoint = endPoint;  
             this.startPoint = startPoint;  
             this.routingEngine = routingEngine;  
             this.barrierFeatureSource = barrierFeatureSource;  
 
             this.stopPoints = new List<PointShape>(stopPoints);  
             this.avoidableFeatureIds = new List<string>(avoidableFeatureIds);  
 
             routingEngine.RoutingAlgorithm.FindingRoute += RoutingAlgorithm_FindingRoute;  
         }  
 
         public PointShape StartPoint  
         {  
             get { return startPoint; }  
             set { startPoint = value; }  
         }  
 
         public PointShape EndPoint  
         {  
             get { return endPoint; }  
             set { endPoint = value; }  
         }  
 
         public List<PointShape> StopPoints  
         {  
             get { return stopPoints; }  
         }  
 
         public RoutingEngine RoutingEngine  
         {  
             get { return routingEngine; }  
             set { routingEngine = value; }  
         }  
 
         public FeatureSource BarrierFeatureSource  
         {  
             get { return barrierFeatureSource; }  
             set { barrierFeatureSource = value; }  
         }  
 
         public List<string> AvoidableFeatureIds  
         {  
             get { return avoidableFeatureIds; }  
         }  
 
 
         public RoutingResult GetRoute()  
         {  
             if (stopPoints != null && !stopPoints.Any())  
             {  
                 RoutingResult result = routingEngine.GetRoute(startPoint, endPoint);  
                 return result;  
             }  
             else  
             {  
                 Collection<PointShape> points = new Collection<PointShape>();  
                 points.Add(startPoint);  
 
                 foreach (PointShape stopPoint in stopPoints)  
                 {  
                     points.Add(stopPoint);  
                 }  
 
                 points.Add(endPoint);  
 
                 // Filter the invalid point.  
                 Collection<PointShape> availablePoint = FilterInvalidPoints(points);  
 
                 RoutingResult result = null;  
                 for (int i = 0; i < availablePoint.Count - 1; i++)  
                 {  
                     RoutingResult tempResult = routingEngine.GetRoute(availablePoint[i], availablePoint[i|+ 1]);  
                     result = CombineRoutingResult(result, tempResult);  
                 }  
 
                 return result;  
             }  
         }  
 
         private Collection<PointShape> FilterInvalidPoints(IEnumerable<PointShape> points)  
         {  
             Collection<PointShape> result = new Collection<PointShape>();  
 
             barrierFeatureSource.Open();  
             Collection<Feature> barrierFeatures = barrierFeatureSource.GetAllFeatures(ReturningColumnsType.NoColumns);  
             foreach (PointShape point in points)  
             {  
                 bool inBarrier = barrierFeatures.Any(a => a.Contains(new Feature(point)));  
                 if (!inBarrier) result.Add(point);  
             }  
 
             return result;  
         }  
 
         private static RoutingResult CombineRoutingResult(RoutingResult baseResult, RoutingResult additionalResult)  
         {  
             if (baseResult == null)  
             {  
                 baseResult = new RoutingResult();  
                 baseResult.Distance = additionalResult.Distance;  
                 baseResult.Weight = additionalResult.Weight;  
                 baseResult.Route = additionalResult.Route;  
 
                 additionalResult.Features.ForEach(a => baseResult.Features.Add(a));  
                 additionalResult.OrderedStops.ForEach(a => baseResult.OrderedStops.Add(a));  
                 additionalResult.RouteSegments.ForEach(a => baseResult.RouteSegments.Add(a));  
             }  
             else  
             {  
                 baseResult.Distance += additionalResult.Distance;  
                 baseResult.Weight += additionalResult.Weight;  
 
                 Collection<Vertex> vertexes = new Collection<Vertex>();  
                 baseResult.Route.Vertices.ForEach(vertexes.Add);  
                 additionalResult.Route.Vertices.ForEach(vertexes.Add);  
 
                 baseResult.Route = new LineShape(vertexes);  
                 additionalResult.Features.ForEach(a => baseResult.Features.Add(a));  
                 additionalResult.OrderedStops.ForEach(a => baseResult.OrderedStops.Add(a));  
                 additionalResult.RouteSegments.ForEach(a => baseResult.RouteSegments.Add(a));  
             }  
 
             return baseResult;  
         }  
 
         private void RoutingAlgorithm_FindingRoute(object sender, FindingRouteRoutingAlgorithmEventArgs e)  
         {  
             Collection<string> beContainedFeatureIds = new Collection<string>();  
             barrierFeatureSource.Open();  
 
             Collection<string> startPointAdjacentIds = e.RouteSegment.StartPointAdjacentIds;  
             Collection<string> endPointAdjacentIds = e.RouteSegment.EndPointAdjacentIds;  
 
             foreach (string id in startPointAdjacentIds.Where(id => avoidableFeatureIds.Contains(id)))  
             {  
                 beContainedFeatureIds.Add(id);  
             }  
 
             foreach (string id in endPointAdjacentIds.Where(id => avoidableFeatureIds.Contains(id)))  
             {  
                 beContainedFeatureIds.Add(id);  
             }  
 
             // Remove the ones that be contained in the avoidable area  
             foreach (string id in beContainedFeatureIds)  
             {  
                 if (e.RouteSegment.StartPointAdjacentIds.Contains(id))  
                 {  
                     e.RouteSegment.StartPointAdjacentIds.Remove(id);  
                 }  
                 if (e.RouteSegment.EndPointAdjacentIds.Contains(id))  
                 {  
                     e.RouteSegment.EndPointAdjacentIds.Remove(id);  
                 }  
             }  
         }  
     }  
 }  
 

StopItemViewModel.cs

 using System;  
 using System.Windows.Media.Imaging;  
 using ThinkGeo.MapSuite.Core;  
 
 namespace ThinkGeo.MapSuite.RoutingExamples  
 {  
     public class StopItemViewModel : ViewModelBase  
     {  
         private const string markerImageSourceUri = "pack://application:,,,/CityRoutingAndDirections;Component/Image/stop.png";  
 
         private BitmapImage markerImageSource;  
         private PointShape location;  
 
         public StopItemViewModel()  
             : this(null)  
         { }  
 
         public StopItemViewModel(PointShape location)  
         {  
             this.location = location;  
             this.MarkerImageSource = new BitmapImage(new Uri(markerImageSourceUri, UriKind.RelativeOrAbsolute));  
         }  
 
         public BitmapImage MarkerImageSource  
         {  
             get { return markerImageSource; }  
             set  
             {  
                 markerImageSource = value;  
                 RaisePropertyChanged(() => MarkerImageSource);  
             }  
         }  
 
         public PointShape Location  
         {  
             get { return location; }  
             set  
             {  
                 location = value;  
                 RaisePropertyChanged(() => Location);  
             }  
         }  
     }  
 }