A sample for the required functionality:
public void AddMarker(RadMap Map)
{
SearchRequest r = new SearchRequest();
r.Query = "Paris, France";
r.UserData = new Guid();
bingProvider.SearchCompleted += BingProvider_SearchCompleted;
bingProvider.SearchAsync(r);
}
private void BingProvider_SearchCompleted(object sender, SearchCompletedEventArgs e)
{
//one cannot access the UserData here
}
How to reproduce: Check the attached project and video
Workaround: force an update in the MapElement
Public Class RadForm1
Private bingKey As String = ""
Dim myTimer As Timer
Public Sub New()
InitializeComponent()
Dim bingProvider As BingRestMapProvider = New Telerik.WinControls.UI.BingRestMapProvider()
bingProvider.UseSession = True
bingProvider.BingKey = bingKey
AddHandler bingProvider.SearchCompleted, AddressOf bingProvider_SearchCompleted
Me.RadMap1.Providers.Add(bingProvider)
myTimer = New Timer
myTimer.Interval = 500
AddHandler myTimer.Tick, AddressOf OnMyyTimerTick
End Sub
Private Function OnMyyTimerTick() As Object
myTimer.Stop()
Me.RadMap1.MapElement.InvalidateMeasure(True)
End Function
Private Sub bingProvider_SearchCompleted(sender As Object, e As SearchCompletedEventArgs)
myTimer.Start()
End Sub
End Class
In WPF this is possible with custom provider: https://www.telerik.com/forums/map-control-and-web-map-service
To reproduce: The TileSize property of the LocalMapProvider is readonly.
Workaround:
public class CustomLocalMapProvider : LocalMapProvider
{
public CustomLocalMapProvider()
{
FieldInfo fi = typeof(LocalMapProvider).GetField("tileSize", BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, new Size(200,200));
}
}
https://msdn.microsoft.com/en-us/library/ff701717.aspx
How to reproduce: check the attached project, the expected behavior would be that the MapPoint object have its text painted
Workaround:
public partial class RadForm1 : Telerik.WinControls.UI.RadForm
{
public RadForm1()
{
InitializeComponent();
MapLayer pinsLayer = new MapLayer("Buildings Layout");
this.radMap1.Layers.Add(pinsLayer);
EmptyMapProvider emptyProvider = new EmptyMapProvider();
emptyProvider.InitializationComplete += emptyProvider_InitializationComplete;
this.radMap1.Providers.Add(emptyProvider);
using (FileStream seatsStream = File.OpenRead(@"..\..\shapes-new\Label_Pk_Boulou2.shp"))
{
using (FileStream seatsDataStream = File.OpenRead(@"..\..\shapes-new\Label_Pk_Boulou2.dbf"))
{
ShapeFileReaderParameters parameters = new ShapeFileReaderParameters();
parameters.ShapeStream = seatsStream;
parameters.DbfStream = seatsDataStream;
//parameters.CoordinateConverter = new EPSG900913Converter();
ShapeFileReader reader = new ShapeFileReader();
List<MapVisualElement> elements = reader.Read(parameters);
foreach (var item in elements)
{
item.Text = Convert.ToString(((IExtendedData)item).ExtendedData["Text"]);
}
this.radMap1.Layers["Buildings Layout"].AddRange(elements);
}
}
}
}
To reproduce: use the ToolTipTextNeeded event to assign some tool tips for the MapRoutes. You will notice that the tool tips are shown not only when you hover the route line but also around it.
To reproduce:
public RadForm1()
{
InitializeComponent();
this.radMap1.ToolTipTextNeeded += radMap1_ToolTipTextNeeded;
BingRestMapProvider bingProvider = new Telerik.WinControls.UI.BingRestMapProvider();
bingProvider.UseSession = true;
bingProvider.BingKey = bingKey;
this.radMap1.Providers.Add(bingProvider);
//add a layer to display the route
this.radMap1.MapElement.Layers.Add(new MapLayer());
RouteRequest request = new RouteRequest();
request.DistanceUnit = DistanceUnit.Kilometer;
request.Options.Mode = TravelMode.Driving;
request.Options.Optimization = RouteOptimization.Time;
request.Options.RouteAttributes = RouteAttributes.RoutePath;
request.Options.RouteAvoidance = RouteAvoidance.None;
request.Waypoints.Add("Paris, France");
request.Waypoints.Add("Madrid, Spain");
bingProvider.CalculateRouteCompleted += BingProvider_RoutingCompleted;
bingProvider.CalculateRouteAsync(request);
}
private void radMap1_ToolTipTextNeeded(object sender, Telerik.WinControls.ToolTipTextNeededEventArgs e)
{
Console.WriteLine(sender);
}
private void BingProvider_RoutingCompleted(object sender, RoutingCompletedEventArgs e)
{
List<PointG> pts = new List<PointG>();
Telerik.WinControls.UI.Map.PointG startPoint = new Telerik.WinControls.UI.Map.PointG(e.Route.RoutePath.Line.Coordinates.First()[0], e.Route.RoutePath.Line.Coordinates.First()[1]);
pts.Add(startPoint);
Telerik.WinControls.UI.Map.PointG endPoint = new Telerik.WinControls.UI.Map.PointG(e.Route.RoutePath.Line.Coordinates.Last()[0], e.Route.RoutePath.Line.Coordinates.Last()[1]);
pts.Add(endPoint);
MapPolyline mapPolyline = new MapPolyline(pts);
mapPolyline.BackColor = Color.Red;
mapPolyline.BorderColor = Color.Red;
mapPolyline.BorderWidth = 5;
this.radMap1.MapElement.Layers[0].Add(mapPolyline);
PointG midPoint = new PointG((startPoint.Latitude + endPoint.Latitude) / 2d, (startPoint.Longitude + endPoint.Longitude) / 2d);
MapLabel westernLabel = new MapLabel(midPoint, "My label")
{
BackColor = Color.FromArgb(122, 255, 0, 0)
};
this.radMap1.MapElement.Layers[0].Add(westernLabel);
}
Workaround:
public class CustomMapPolyline : MapPolyline
{
List<GraphicsPath> paths;
public CustomMapPolyline(IEnumerable<PointG> points) : base(points)
{
}
public override void ViewportChanged(IMapViewport viewport, ViewportChangeAction action)
{
base.ViewportChanged(viewport, action);
FieldInfo fi = typeof(MapPolyline).GetField("paths", BindingFlags.Instance | BindingFlags.NonPublic);
this.paths = (List<GraphicsPath>)fi.GetValue(this);
}
public override bool HitTest(PointG pointG, PointL pointL, IMapViewport viewport)
{
using (Pen pen = new Pen(this.BorderColor, this.BorderWidth))
{
foreach (GraphicsPath path in this.paths)
{
if (path.IsOutlineVisible(pointL.X, pointL.Y, pen))
{
return true;
}
}
}
return false;
}
}
Workaround:
Public Class MyLocalMapProvider
Inherits LocalMapProvider
Public Overrides Sub ViewportChanged(viewport As IMapViewport, action As ViewportChangeAction)
If Not Me.Initialized Then
Me.Initialize()
Return
End If
Dim tilesToDraw As List(Of MapVisualElement) = DirectCast(Me.GetType().BaseType.GetField("tilesToDraw", BindingFlags.Instance Or BindingFlags.NonPublic).GetValue(Me), List(Of MapVisualElement))
Dim numOfTilesX As Integer = CInt(Math.Ceiling(CDbl((viewport.ViewportInPixels.Width)) / Me.TileSize.Width)) + 2
Dim numOfTilesY As Integer = CInt(Math.Ceiling(CDbl((viewport.ViewportInPixels.Height)) / Me.TileSize.Height)) + 2
Dim maxNumberOfTilesY As Integer = If((viewport.ZoomLevel = 1), 2, (viewport.ZoomLevel - 1) << 2)
numOfTilesY = Math.Min(numOfTilesY, maxNumberOfTilesY)
Dim topLeftTile As Point = MapTileSystemHelper.PixelXYToTileXY(-viewport.PanOffset.Width, -viewport.PanOffset.Height)
Dim numberOfTiles As Integer = 2 << (viewport.ZoomLevel - 1)
Dim startX As Integer = CInt(viewport.PanOffset.Width) Mod Me.TileSize.Width
Dim startY As Integer = CInt(viewport.PanOffset.Height) Mod Me.TileSize.Height
If startX > 0 Then
startX -= Me.TileSize.Width
End If
For i As Integer = 0 To numOfTilesY - 1
For j As Integer = 0 To numOfTilesX - 1
Dim x As Integer = startX + j * Me.TileSize.Width
Dim y As Integer = startY + i * Me.TileSize.Height
Dim tileX As Integer = (topLeftTile.X + j) Mod numberOfTiles
Dim tileY As Integer = (topLeftTile.Y + i) Mod numberOfTiles
If tileX < 0 Then
tileX += numberOfTiles
End If
tilesToDraw.Add(New MapTile(Me.GetTileImage(tileX, tileY, viewport.ZoomLevel), New Rectangle(New Point(x, y), Me.TileSize)))
Next
Next
End Sub
End Class
How to reproduce: Change the current culture so that a comma is used as a decimal separator, the Elevations example will fail with a (400) Bar Request error.
Workaround: create a custom BingRestMapProvider class
public class CustomBingRestMapProvider : BingRestMapProvider
{
protected override string GetPointsString(List<PointG> points)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < points.Count; i++)
{
PointG point = points[i];
if (i > 0)
{
sb.Append(",");
}
sb.Append(point.Latitude.ToString(CultureInfo.InvariantCulture) + "," + point.Longitude.ToString(CultureInfo.InvariantCulture));
}
return sb.ToString();
}
}
To reproduce: - Use a DataTable as a data source for SqlGeospatialDataReader. - An exception will occur. Workaround: Convert the data table to a simple list of custom objects.
Until released use the following custom implementation:
public partial class RoadOnDemandForm : RadForm
{
public RoadOnDemandForm()
{
InitializeComponent();
string cacheFolder = @"..\..\cache";
BingRestMapProvider bingProvider = new MyBingRestMapProvider();
bingProvider.Culture = System.Threading.Thread.CurrentThread.CurrentCulture;
bingProvider.ImagerySet = ImagerySet.Road;
bingProvider.UseSession = true;
bingProvider.BingKey = "YourApiKey";
LocalFileCacheProvider cache = new LocalFileCacheProvider(cacheFolder);
bingProvider.CacheProvider = cache;
this.radMap1.MapElement.Providers.Add(bingProvider);
}
}
public class MyBingRestMapProvider : BingRestMapProvider
{
private const string ImageryMetadataServiceUri = "https://dev.virtualearth.net/REST/v1/Imagery/Metadata/{set}?output=json&key={key}&c={culture}&dir={directory}";
protected override void InitializeImageryService()
{
typeof(BingRestMapProvider).GetField("tileMetadataInfo", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(this, null);
try
{
string uriString = ImageryMetadataServiceUri;
uriString = uriString.Replace("{set}", "RoadOnDemand");
uriString = uriString.Replace("{key}", string.IsNullOrEmpty(this.SessionId) ? this.BingKey : this.SessionId);
uriString = uriString.Replace("{culture}", this.Culture.ToString());
uriString = uriString.Replace("{directory}", "0");
WebClient client = new WebClient();
client.DownloadStringCompleted += this.InitializeImageryMetadataCompleted;
client.DownloadStringAsync(new Uri(uriString, UriKind.Absolute));
}
catch (Exception ex)
{
throw new Exception(string.Format("Imagery Service Exception: {0}", ex.Message));
}
}
}
Error:
System.ArgumentException was unhandled
HResult=-2147024809
Message=An item with the same key has already been added.
Source=mscorlib
StackTrace:
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Telerik.WinControls.UI.DbfHeader.CreateExtendedPropertySet()
at Telerik.WinControls.UI.DbfReader..ctor(Stream stream, ExtendedPropertySet propertySet, Encoding encoding)
at Telerik.WinControls.UI.ShapeFileReader.Read(ShapeFileReaderParameters parameters)
at _1125357MapShapeFiles.RadForm1..ctor() in d:\Projects\1125357MapShapeFiles\RadForm1.cs:line 37
at _1125357MapShapeFiles.Program.Main() in d:\Projects\1125357MapShapeFiles\Program.cs:line 17
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
How to reproduce:
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
MapLayer pointLayer = new MapLayer("PointG");
pointLayer.ClusterStrategy = new ElementClusterStrategy();
pointLayer.ClusterDistance = 100;
this.radMap1.Layers.Add(pointLayer);
MapPin pin1 = new MapPin(new PointG(45d, 15d)) { BackColor = Color.Coral, ToolTipText = "Tool Tip1" };
MapPin pin2 = new MapPin(new PointG(44d, 18d)) { BackColor = Color.Coral, ToolTipText = "Tool Tip2" };
this.radMap1.Layers["PointG"].Add(pin1);
this.radMap1.Layers["PointG"].Add(pin2);
this.SetupProviders();
}
private void radMap1_ToolTipTextNeeded(object sender, Telerik.WinControls.ToolTipTextNeededEventArgs e)
{
MapCluster cluster = sender as MapCluster;
if (cluster != null && cluster.ClusteredItems.Count == 1)
{
cluster.ToolTipText = ((MapPin)cluster.ClusteredItems[0]).ToolTipText;
}
}
private void SetupProviders()
{
string cacheFolder = @"..\..\cache";
BingRestMapProvider bingProvider = new BingRestMapProvider();
bingProvider.Culture = System.Threading.Thread.CurrentThread.CurrentCulture;
bingProvider.ImagerySet = ImagerySet.Road;
bingProvider.UseSession = true;
bingProvider.BingKey = "...";
LocalFileCacheProvider cache = new LocalFileCacheProvider(cacheFolder);
bingProvider.CacheProvider = cache;
this.radMap1.MapElement.Providers.Add(bingProvider);
bingProvider.InitializationComplete += bingProvider_InitializationComplete;
}
private void bingProvider_InitializationComplete(object sender, EventArgs e)
{
this.radMap1.BringIntoView(new PointG(45d, 15d), 5);
}
}
Workaround: handle the ToolTipNeededEvent
private void radMap1_ToolTipTextNeeded(object sender, Telerik.WinControls.ToolTipTextNeededEventArgs e)
{
MapCluster cluster = sender as MapCluster;
if (cluster != null && cluster.ClusteredItems.Count == 1)
{
cluster.ToolTipText = ((MapPin)cluster.ClusteredItems[0]).ToolTipText;
}
}
You can find attached a sample project, video, demonstrating the steps and a screenshot of the error.
Workaround:
public class MyMapVisualElementFactory : MapVisualElementFactory
{
public override MapVisualElement CreatePolyline(Collection<PointG> points)
{
return new MyMapPolyline(points);
}
}
public class MyMapPolyline : MapPolyline
{
private FieldInfo pathsField;
private FieldInfo boundingRectsField;
private FieldInfo isInViewportField;
public MyMapPolyline(Collection<PointG> points) : base(points)
{
this.pathsField = typeof(MapPolyline).GetField("paths", BindingFlags.Instance | BindingFlags.NonPublic);
this.boundingRectsField = typeof(MapPolyline).GetField("boundingRects", BindingFlags.Instance | BindingFlags.NonPublic);
this.isInViewportField = typeof(MapPolyline).GetField("isInViewport", BindingFlags.Instance | BindingFlags.NonPublic);
}
public override void ViewportChanged(IMapViewport viewport, ViewportChangeAction action)
{
if ((action & ViewportChangeAction.All) == action)
{
long mapSize = MapTileSystemHelper.MapSize(viewport.ZoomLevel);
List<GraphicsPath> paths = new List<GraphicsPath>();
List<RectangleL> boundingRects = new List<RectangleL>();
long start = viewport.PanOffset.Width;
int maxWraparounds = 1;
while (start + mapSize < viewport.ViewportInPixels.Width)
{
maxWraparounds++;
start += mapSize;
}
for (int i = -1; i <= maxWraparounds; i++)
{
GraphicsPath path = new GraphicsPath();
List<PointF> drawPoints = new List<PointF>();
foreach (PointG p in this.Points)
{
PointL pixel = MapTileSystemHelper.LatLongToPixelXY(p.Latitude, p.Longitude, viewport.ZoomLevel);
drawPoints.Add(new PointF(pixel.X + i * mapSize, pixel.Y));
}
path.AddLines(drawPoints.ToArray());
RectangleF rect = path.GetBounds();
RectangleF view = new RectangleF(viewport.ViewportInPixels.X, viewport.ViewportInPixels.Y,
viewport.ViewportInPixels.Width, viewport.ViewportInPixels.Height);
if (rect.IntersectsWith(view))
{
paths.Add(path);
}
boundingRects.Add(new RectangleL((long)rect.X, (long)rect.Y, (long)rect.Width, (long)rect.Height));
}
this.pathsField.SetValue(this, paths);
this.boundingRectsField.SetValue(this, boundingRects);
}
if (action != ViewportChangeAction.None)
{
this.isInViewportField.SetValue(this, false);
List<RectangleL> boundingRects = this.boundingRectsField.GetValue(this) as List<RectangleL>;
foreach (RectangleL rect in boundingRects)
{
if (viewport.ViewportInPixels.IntersectsWith(rect))
{
this.isInViewportField.SetValue(this, true);
}
}
}
}
}
public class MyMapVisualElementFactory : MapVisualElementFactory
{
public override MapVisualElement CreatePolyline(Collection<PointG> points)
{
return new MyMapPolyline(points);
}
}
public class MyMapPolyline : MapPolyline
{
private FieldInfo pathsField;
private FieldInfo boundingRectsField;
private FieldInfo isInViewportField;
public MyMapPolyline(Collection<PointG> points) : base(points)
{
this.pathsField = typeof(MapPolyline).GetField("paths", BindingFlags.Instance | BindingFlags.NonPublic);
this.boundingRectsField = typeof(MapPolyline).GetField("boundingRects", BindingFlags.Instance | BindingFlags.NonPublic);
this.isInViewportField = typeof(MapPolyline).GetField("isInViewport", BindingFlags.Instance | BindingFlags.NonPublic);
}
public override void ViewportChanged(IMapViewport viewport, ViewportChangeAction action)
{
if ((action & ViewportChangeAction.All) == action)
{
long mapSize = MapTileSystemHelper.MapSize(viewport.ZoomLevel);
List<GraphicsPath> paths = new List<GraphicsPath>();
List<RectangleL> boundingRects = new List<RectangleL>();
long start = viewport.PanOffset.Width;
int maxWraparounds = 1;
while (start + mapSize < viewport.ViewportInPixels.Width)
{
maxWraparounds++;
start += mapSize;
}
for (int i = -1; i <= maxWraparounds; i++)
{
GraphicsPath path = new GraphicsPath();
List<PointF> drawPoints = new List<PointF>();
foreach (PointG p in this.Points)
{
PointL pixel = MapTileSystemHelper.LatLongToPixelXY(p.Latitude, p.Longitude, viewport.ZoomLevel);
drawPoints.Add(new PointF(pixel.X + i * mapSize, pixel.Y));
}
path.AddLines(drawPoints.ToArray());
RectangleF rect = path.GetBounds();
RectangleF view = new RectangleF(viewport.ViewportInPixels.X, viewport.ViewportInPixels.Y,
viewport.ViewportInPixels.Width, viewport.ViewportInPixels.Height);
if (rect.IntersectsWith(view))
{
paths.Add(path);
}
boundingRects.Add(new RectangleL((long)rect.X, (long)rect.Y, (long)rect.Width, (long)rect.Height));
}
this.pathsField.SetValue(this, paths);
this.boundingRectsField.SetValue(this, boundingRects);
}
if (action != ViewportChangeAction.None)
{
this.isInViewportField.SetValue(this, false);
List<RectangleL> boundingRects = this.boundingRectsField.GetValue(this) as List<RectangleL>;
foreach (RectangleL rect in boundingRects)
{
if (viewport.ViewportInPixels.IntersectsWith(rect))
{
this.isInViewportField.SetValue(this, true);
}
}
}
}
}
How to reproduce: change the Windows culture to Greek and start the OSM example
How to reproduce: check the attached video
Workaround: create a custom MapSearchBarElement
public class MyRadMap : RadMap
{
public override string ThemeClassName
{
get
{
return typeof(RadMap).FullName;
}
}
protected override RadMapElement CreateMapElement()
{
return new MyRadMapElement();
}
}
public class MyRadMapElement : RadMapElement
{
protected override Type ThemeEffectiveType
{
get
{
return typeof(RadMapElement);
}
}
protected override MapSearchBarElement CreateSearchBarElement()
{
return new MyMapSearchBarElement(this);
}
}
public class MyMapSearchBarElement : MapSearchBarElement
{
public MyMapSearchBarElement(MyRadMapElement mapElement)
: base(mapElement)
{ }
protected override Type ThemeEffectiveType
{
get
{
return typeof(MapSearchBarElement);
}
}
protected override void SearchProviderSearchError(object sender, SearchErrorEventArgs e)
{
IMapSearchProvider provider = sender as IMapSearchProvider;
provider.SearchCompleted -= SearchProviderSearchCompleted;
provider.SearchError -= SearchProviderSearchError;
if (this.ElementTree != null)
{
UnsubscribeToTextBoxEvents(this.SearchTextBoxElement);
RadMessageBox.SetThemeName(this.ElementTree.ThemeName);
RadMessageBox.Show(e.Error.Message);
SubscribeToTextBoxEvents(this.SearchTextBoxElement);
}
}
protected override void SubscribeToTextBoxEvents(RadTextBoxElement textBox)
{
textBox.TextChanged += OnSearchTextBoxTextChanged;
textBox.KeyDown += OnSearchTextBoxKeyDown;
}
protected override void UnsubscribeToTextBoxEvents(RadTextBoxElement textBox)
{
textBox.TextChanged -= OnSearchTextBoxTextChanged;
textBox.KeyDown -= OnSearchTextBoxKeyDown;
}
private void OnSearchTextBoxKeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
this.Search(this.SearchTextBoxElement.Text);
}
}
}