In the scenario below one should be able to access the defined UserData value in the SearchCompleted event handler
How to reproduce:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.radMap1.ShowSearchBar = true;
BingRestMapProvider bingProvider = this.radMap1.Providers[0] as BingRestMapProvider;
this.radMap1.MapElement.SearchBarElement.SearchProvider = bingProvider;
this.radMap1.MapElement.SearchBarElement.SearchProvider.SearchCompleted += BingProvider_SearchCompleted;
}
private void BingProvider_SearchCompleted(object sender, SearchCompletedEventArgs e)
{
Telerik.WinControls.UI.Map.RectangleG allPoints = new Telerik.WinControls.UI.Map.RectangleG(double.MinValue, double.MaxValue, double.MaxValue, double.MinValue);
this.radMap1.Layers["Pins"].Clear();
foreach (Telerik.WinControls.UI.Map.Bing.Location location in e.Locations)
{
Telerik.WinControls.UI.Map.PointG point = new Telerik.WinControls.UI.Map.PointG(location.Point.Coordinates[0], location.Point.Coordinates[1]);
MapPin pin = new MapPin(point);
pin.Size = new System.Drawing.Size(20, 40);
pin.BackColor = Color.Red;
pin.ToolTipText = location.Address.FormattedAddress;
this.radMap1.MapElement.Layers["Pins"].Add(pin);
allPoints.North = Math.Max(allPoints.North, point.Latitude);
allPoints.South = Math.Min(allPoints.South, point.Latitude);
allPoints.West = Math.Min(allPoints.West, point.Longitude);
allPoints.East = Math.Max(allPoints.East, point.Longitude);
}
if (e.Locations.Length > 0)
{
if (e.Locations.Length == 1)
{
this.radMap1.BringIntoView(new Telerik.WinControls.UI.Map.PointG(e.Locations[0].Point.Coordinates[0], e.Locations[0].Point.Coordinates[1]));
}
else
{
this.radMap1.MapElement.BringIntoView(allPoints);
this.radMap1.Zoom(this.radMap1.MapElement.ZoomLevel - 1);
}
}
else
{
RadMessageBox.Show("No result found for the provided search query!");
}
}
Telerik.WinControls.UI.Map.Bing.SearchRequest request;
private void radButton1_Click(object sender, EventArgs e)
{
Telerik.WinControls.UI.MapLayer pinsLayer = new MapLayer("Pins");
this.radMap1.Layers.Add(pinsLayer);
request = new SearchRequest();
request.Query = "San Marino";
request.SearchOptions.Count = 10;
request.SearchOptions.QueryParse = true;
request.UserData = "Tooltip";
BingRestMapProvider bingProvider = this.radMap1.Providers[0] as BingRestMapProvider;
bingProvider.SearchAsync(request);
}
Workaround: if possible cache the data to be accessed at a later stage
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);
}
}
}
}
}
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
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;
}
}
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);
}
}
}
}
1. Open the demo application >> Map >> Search example.
2. Enter some text and press Enter.
3. Move the mouse a little bit and you will notice the search box looses focus.
Workaround: this.radMap1.MapElement.SearchBarElement.SearchTextBoxElement.TextBoxItem.LostFocus+=TextBoxItem_LostFocus;
private void TextBoxItem_LostFocus(object sender, EventArgs e)
{
this.radMap1.MapElement.SearchBarElement.SearchTextBoxElement.TextBoxItem.TextBoxControl.Focus();
}
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);
}
}
}
How to reproduce: change the Windows culture to Greek and start the OSM example
https://msdn.microsoft.com/en-us/library/ff701717.aspx
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;
}
}
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));
}
}
}
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));
}
}
To reproduce:
set the clustering and add some pins upon a button click.
Workaround
Refresh with the following method:
Please refer to the sample project and follow the steps:
1. Run the attached application.
Recently OpenStreetMap changed their tile usage policy and require UserAgent string in the web headers for accessing tile.openstreetmap.org tiles.
https://operations.osmfoundation.org/policies/tiles/
As a result, standard open street map mode does not work - no tiles are loaded and "too many requests" error is returned from the server.
RadMap's OpenStreetMapProvider needs API (event, property or similar) for easier set up of UserAgent / Referer / other headers of web requests.
Hello,
I am using RadMap to display a KML file.
Unfortunately, it looks like RadMap is not displaying properly all the shapes (departments).
Displayed with RadMap (few holes, ie departments not displayed):
Displayed with a third party tool (all departments properly displayed):
I have attached the KML file in a zip file.
Best,
Olivier