How to animate a draggable pushpin
I'm looking for a way to show the motion of a push-pin being dragged over the map. I've tried to modify an example proposed here: http://peteohanlon.wordpress.com/2010/10/10/draggable-pushpins/ by updating the AssociatedObject.Location开发者_运维问答 in delegate added to MouseMove event handler, but this makes no results. The push-pin remains at it's place till the moment when the mouse button is released. Then it jumps to the new location.
Any idea how can I force the MapLayer to keep track of the push-pin location during the drag and redraw it properly as mouse moves?
Max, can you clarify what you want to do? Your approach here sounds reasonable, but having the map recalculate the pin's location every time the mouse moves is a bit uneeded. What about something like this?:
When the pin goes into drag mode, it's removed from the map and replaced with a draggable pin that only exists in screen space. So the user is dragging the "pin" around in screen-space, not map space.
When the user ends the drag you convert the screen position to map position (a Location object), and then add it back to the map.
I came across this while working up my own solution, and I was so happy to see it working exactly as you describe I figured I'd post it. To note, I am also using a 2Way MVVM Binding pattern and it works flawlessly. You need 2 things:
1) This extension method to help find the MapLayer that is parent to the pin at runtime:
public static T FindVisualParent<T>(this DependencyObject obj)
where T : DependencyObject
{
DependencyObject parent = VisualTreeHelper.GetParent(obj);
while (parent != null)
{
T typed = parent as T;
if (typed != null)
{
return typed;
}
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
2) In the Dragging event handler on the pushpin, call that extension method to reference hosting MapLayer and then fire off the most beauteous InvalidateArrange method (from UIElement) as follows:
void ParentMap_MouseMove(object sender, MouseEventArgs e)
{
var map = sender as Microsoft.Maps.MapControl.Map;
var parentLayer = this.FindVisualParent<MapLayer>();
if (this.isDragging)
{
var mouseMapPosition = e.GetPosition(map);
var mouseGeocode = map.ViewportPointToLocation(mouseMapPosition);
this.Location = mouseGeocode;
parentLayer.InvalidateArrange();
}
}
That should asynchronously perform the visual update and give you a nice slide-around behavior on the pin drag. HTH
There is a ready to use solution in the Silverlight Toolkit for WP7 over the GestureListener:
<my:Pushpin Location="{Binding Location}">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener DragDelta="GestureListener_DragDelta" DragStarted="GestureListener_DragStarted" DragCompleted="GestureListener_DragCompleted"/>
</toolkit:GestureService.GestureListener>
</my:Pushpin>
private void GestureListener_DragStarted(object sender, DragStartedGestureEventArgs e)
{
Map.IsEnabled = false;
}
private void GestureListener_DragCompleted(object sender, DragCompletedGestureEventArgs e)
{
Map.IsEnabled = true;
}
private void GestureListener_DragDelta(object sender, DragDeltaGestureEventArgs e)
{
Point p = e.GetPosition(Map);
App.ViewModel.Location = Map.ViewportPointToLocation(p);
}
精彩评论