Hi Guys,
I have a WPF app which has a RadMap with 2 layers. The first layer is a dynamic layer which contains lots of MapPolygons loaded from shape files with the background colour set according to the metadata in the shape file. The second layer is an information layer with lots of MapPinPoints which sit on top of the shapes in the dynamic layer.
This app is going onto a ruggadised tablet and will be used in direct sunlight, and as such the users would like a good contrast between the text on the MapPinPoints and the MapPolygons they sit on top of. I've written the code to change the fonts and this works really well when I can get it to execute. The problem I have is trying to figure out when the dynamic layer has finished rendering so that it's .Items property actually has something in it and I can check which polygons a pinpoint falls into.
I have tried hooking into various events such as LayoutUpdated, SizeChanged, etc.. I even created my own event on the MapDynamicSource to notify me when the ItemRequest is complete, but the Items collection is still empty at this point...
Both layers change fairly regularly and so the Loaded event doesn't help me either because it only fires once.
If you need any more info please let me know, otherwise any help would be really appreciated.
Thanks,
Stuart
I have a WPF app which has a RadMap with 2 layers. The first layer is a dynamic layer which contains lots of MapPolygons loaded from shape files with the background colour set according to the metadata in the shape file. The second layer is an information layer with lots of MapPinPoints which sit on top of the shapes in the dynamic layer.
This app is going onto a ruggadised tablet and will be used in direct sunlight, and as such the users would like a good contrast between the text on the MapPinPoints and the MapPolygons they sit on top of. I've written the code to change the fonts and this works really well when I can get it to execute. The problem I have is trying to figure out when the dynamic layer has finished rendering so that it's .Items property actually has something in it and I can check which polygons a pinpoint falls into.
I have tried hooking into various events such as LayoutUpdated, SizeChanged, etc.. I even created my own event on the MapDynamicSource to notify me when the ItemRequest is complete, but the Items collection is still empty at this point...
Both layers change fairly regularly and so the Loaded event doesn't help me either because it only fires once.
If you need any more info please let me know, otherwise any help would be really appreciated.
Thanks,
Stuart
5 Answers, 1 is accepted
0
Hello Stuart,
I think you can use the DynamicLayer.ItemContainerGenerator.StatusChanged event. When the status is ContainersGenerated then the containers are already generated for polygons. You can attach the Unloaded event for containers to remove pin points when the polygon's container is removed from the layer. Also you can use the Tag property to reference pin points and polygons.
The sample code is below.
All the best,
Andrey Murzov
the Telerik team
I think you can use the DynamicLayer.ItemContainerGenerator.StatusChanged event. When the status is ContainersGenerated then the containers are already generated for polygons. You can attach the Unloaded event for containers to remove pin points when the polygon's container is removed from the layer. Also you can use the Tag property to reference pin points and polygons.
The sample code is below.
private
class
DynamicSource : IMapDynamicSource
{
private
MainWindow page;
private
bool
updateInvoked;
public
DynamicSource(MainWindow examplePage)
{
this
.page = examplePage;
this
.page.dynamicLayer.ItemContainerGenerator.StatusChanged +=
new
EventHandler(ItemContainerGenerator_StatusChanged);
}
private
void
ItemContainerGenerator_StatusChanged(
object
sender, EventArgs e)
{
if
(
this
.page.dynamicLayer.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated
&& !
this
.updateInvoked)
{
this
.updateInvoked =
true
;
this
.page.dynamicLayer.Dispatcher.BeginInvoke(
new
Action(
this
.UpdatePinPoints));
}
}
private
void
UpdatePinPoints()
{
this
.updateInvoked =
false
;
foreach
(MapShape item
in
this
.page.dynamicLayer.Items)
{
if
(item.Tag ==
null
)
{
var containerObject =
this
.page.dynamicLayer.ItemContainerGenerator.ContainerFromItem(item);
var container = containerObject
as
FrameworkElement;
if
(container !=
null
)
{
MapPinPoint point =
new
MapPinPoint()
{
Text =
"test"
,
Foreground =
new
SolidColorBrush(Colors.White)
};
MapLayer.SetLocation(point, item.GeographicalBounds.Center);
MapLayer.SetHotSpot(point,
new
HotSpot()
{
X = 0.5,
Y = 0.5
});
this
.page.informationLayer.Items.Add(point);
item.Tag = point;
container.Unloaded +=
new
RoutedEventHandler(element_Unloaded);
container.Tag = item;
}
}
}
}
private
void
element_Unloaded(
object
sender, RoutedEventArgs e)
{
// container
var container = sender
as
FrameworkElement;
if
(container !=
null
)
{
// polygon
var item = container.Tag
as
FrameworkElement;
container.Tag =
null
;
if
(item !=
null
)
{
// pin point
var point = item.Tag
as
FrameworkElement;
item.Tag =
null
;
if
(point !=
null
)
{
this
.page.informationLayer.Items.Remove(point);
}
}
}
}
// ...
}
All the best,
Andrey Murzov
the Telerik team
Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!
0

Stuart
Top achievements
Rank 1
answered on 02 Aug 2011, 01:06 AM
Hi Andrey,
Thanks for your very detailed response, it certainly feels like I'm a lot closer to a solution. I have followed your sample and hooked into the ItemContainerGenerator.StatusChanged event and this works beautifully, however I still have a bit of an issue because as you'll see in the code below I'm trying to use the dynamic layer's GetItemsInLocation method to determine the shape in which the pinPoint is located. Unfortunately even though the dynamic layer's Items collection is populated, this method returns nothing, whereas is I run the code at a later point (say on map pan) then it works correctly.
Thanks for your very detailed response, it certainly feels like I'm a lot closer to a solution. I have followed your sample and hooked into the ItemContainerGenerator.StatusChanged event and this works beautifully, however I still have a bit of an issue because as you'll see in the code below I'm trying to use the dynamic layer's GetItemsInLocation method to determine the shape in which the pinPoint is located. Unfortunately even though the dynamic layer's Items collection is populated, this method returns nothing, whereas is I run the code at a later point (say on map pan) then it works correctly.
void
ItemContainerGenerator_StatusChanged(
object
sender, EventArgs e)
{
if
(uxShapeFileLayer.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated && !_updateInvoked)
{
_updateInvoked =
true
;
uxShapeFileLayer.Dispatcher.BeginInvoke(
new
Action(UpdatePinPointFontColours));
}
}
private
void
UpdatePinPointFontColours()
{
_updateInvoked =
false
;
if
(uxShapeFileLayer.Items.Count > 0)
{
foreach
(MapPinPoint pinPoint
in
uxInformationLayer.Items)
{
if
(!((
bool
)pinPoint.ExtendedData.GetValue(
"FontColourUpdated"
)))
{
Location pinPointLocation = MapLayer.GetLocation(pinPoint);
List<
object
> shapes = uxShapeFileLayer.GetItemsInLocation(pinPointLocation).ToList();
foreach
(
object
shape
in
shapes)
{
if
(shape
is
MapPolygon || shape
is
MapPolyline)
{
Color inverseStratColour = InvertColour((((MapShape)shape).ShapeFill.Fill
as
SolidColorBrush).Color);
pinPoint.Foreground =
new
SolidColorBrush(inverseStratColour);
pinPoint.ExtendedData.SetValue(
"FontColourUpdated"
,
true
);
break
;
}
}
}
}
}
}
Any ideas?
Many Thanks,
Stuart
0
Hello Stuart,
I think you can use the Loaded event of the shape container. It occurs when the polygon is visible and the GetItemsInLocation could be performed. The sample code is below.
Regards,
Andrey Murzov
the Telerik team
I think you can use the Loaded event of the shape container. It occurs when the polygon is visible and the GetItemsInLocation could be performed. The sample code is below.
public
partial
class
MainWindow : Window
{
private
bool
_attachEventInvoked;
private
bool
_updateInvoked;
void
ItemContainerGenerator_StatusChanged(
object
sender, EventArgs e)
{
if
(uxShapeFileLayer.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated && !_attachEventInvoked)
{
_attachEventInvoked =
true
;
uxShapeFileLayer.Dispatcher.BeginInvoke(
new
Action(AttachEventToContainers));
}
}
private
void
AttachEventToContainers()
{
_attachEventInvoked =
false
;
foreach
(MapShape item
in
uxShapeFileLayer.Items)
{
if
(item.Tag ==
null
)
{
var containerObject =
this
.uxShapeFileLayer.ItemContainerGenerator.ContainerFromItem(item);
var container = containerObject
as
FrameworkElement;
if
(container !=
null
)
{
item.Tag =
true
;
container.Loaded +=
new
RoutedEventHandler(container_Loaded);
}
}
}
}
private
void
container_Loaded(
object
sender, RoutedEventArgs e)
{
if
(!_updateInvoked)
{
_updateInvoked =
true
;
uxShapeFileLayer.Dispatcher.BeginInvoke(
new
Action(UpdatePinPointFontColours));
}
}
private
void
UpdatePinPointFontColours()
{
_updateInvoked =
false
;
if
(uxShapeFileLayer.Items.Count > 0)
{
foreach
(MapPinPoint pinPoint
in
uxInformationLayer.Items)
{
if
(!((
bool
)pinPoint.ExtendedData.GetValue(
"FontColourUpdated"
)))
{
Location pinPointLocation = MapLayer.GetLocation(pinPoint);
List<
object
> shapes = uxShapeFileLayer.GetItemsInLocation(pinPointLocation).ToList();
foreach
(
object
shape
in
shapes)
{
if
(shape
is
MapPolygon || shape
is
MapPolyline)
{
Color inverseStratColour = InvertColour((((MapShape)shape).ShapeFill.Fill
as
SolidColorBrush).Color);
pinPoint.Foreground =
new
SolidColorBrush(inverseStratColour);
pinPoint.ExtendedData.SetValue(
"FontColourUpdated"
,
true
);
break
;
}
}
}
}
}
}
}
Regards,
Andrey Murzov
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get now >>
0

Stuart
Top achievements
Rank 1
answered on 05 Aug 2011, 06:53 AM
Hi Andrey,
Thanks again for the great sample code and for getting back to me so quickly. Unfortunately the GetItemsInLocation method still doesn't work :o( I guess I might need to implement my own algorithm, unless you have any other ideas?
Thanks,
Stuart
Thanks again for the great sample code and for getting back to me so quickly. Unfortunately the GetItemsInLocation method still doesn't work :o( I guess I might need to implement my own algorithm, unless you have any other ideas?
Thanks,
Stuart
0
Hi Stuart,
I have another idea how to do it without using the Loaded event and containers. You can get the geometry of the polygon and use the Geometry.FillContains() method to check the points inside the polygon.
The sample code is below:
Greetings,
Andrey Murzov
the Telerik team
I have another idea how to do it without using the Loaded event and containers. You can get the geometry of the polygon and use the Geometry.FillContains() method to check the points inside the polygon.
The sample code is below:
public
partial
class
MainWindow : Window
{
private
bool
_updateInvoked;
private
bool
initialized;
private
void
ItemContainerGenerator_StatusChanged(
object
sender, EventArgs e)
{
if
(uxShapeFileLayer.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated && !_updateInvoked)
{
_updateInvoked =
true
;
uxShapeFileLayer.Dispatcher.BeginInvoke(
new
Action(UpdatePinPointFontColours));
}
}
private
void
UpdatePinPointFontColours()
{
_updateInvoked =
false
;
var polygonsQuery = from MapPolygon shape
in
uxShapeFileLayer.Items
where shape.Tag ==
null
select shape;
foreach
(MapPolygon item
in
polygonsQuery)
{
item.Tag =
true
;
var polygon = item
as
MapPolygon;
var geometry =
this
.GetGeometry(polygon);
var pointsQuery = from MapPinPoint pinPoint
in
uxInformationLayer.Items
where !(
bool
)pinPoint.ExtendedData.GetValue(
"FontColourUpdated"
)
&& geometry.FillContains((Point)MapLayer.GetLocation(pinPoint))
select pinPoint;
foreach
(MapPinPoint pinPoint
in
pointsQuery)
{
Color inverseStratColour = InvertColour((polygon.ShapeFill.Fill
as
SolidColorBrush).Color);
pinPoint.Foreground =
new
SolidColorBrush(inverseStratColour);
pinPoint.ExtendedData.SetValue(
"FontColourUpdated"
,
true
);
break
;
}
}
}
private
Geometry GetGeometry(MapPolygon mapPolygon)
{
PathGeometry pathGeo =
new
PathGeometry();
PathFigure pathFigure =
new
PathFigure();
PolyLineSegment seg =
new
PolyLineSegment();
PointCollection ponts =
new
PointCollection(mapPolygon.Points.Count);
foreach
(Point point
in
mapPolygon.Points)
{
ponts.Add(point);
}
seg.Points = ponts;
pathFigure.StartPoint = seg.Points[0];
pathFigure.Segments.Add(seg);
pathGeo.Figures.Add(pathFigure);
return
pathGeo;
}
}
Greetings,
Andrey Murzov
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get now >>