I have a custom behavior that allows me to bind a MapControl
extent (bounding box) to the ViewModel; it works by calculating the extent of the map whenever the LoadingStatusChanged
event of the map fires and setting the value of a DependencyProperty
. This works fine -- when the map is panned or zoomed, the bound property in the ViewModel gets updated.
But I would also like the ability to set the extent of the map from the ViewModel and have the map pan/zoom accordingly. I can call TrySetViewBoundsAsync
when the dependency property changes, but the problem is knowing if the dependency property change originated from calculating the extent of the map, or from setting the property in the ViewModel. If it is from calculating the extent, it will change the extent of the map, which will trigger the changed event again, and go off in an infinite loop.
I got around this by adding an IsFromEvent
property and setting it to true whenever the extent is calculated in reaction to the LoadingStatusChanged
event. This prevents the infinite loop but this approach seems...off. It strikes me as hackish and not terribly thread safe.
So...is there a better way to do this? Can the DP be set somehow without causing the PropertyChanged event to fire? Or am I just overthinking this?
public class ExtentBehavior : DependencyObject, IBehavior
{
public DependencyObject AssociatedObject { get; private set; }
public void Attach(Windows.UI.Xaml.DependencyObject associatedObject)
{
AssociatedObject = associatedObject;
var mapControl = associatedObject as MapControl;
mapControl.LoadingStatusChanged += MapLoadingStatusChanged;
}
public static readonly DependencyProperty ExtentProperty =
DependencyProperty.Register("Extent", typeof(MapControl), typeof(ExtentBehavior), new PropertyMetadata(null, OnExtentPropertyChanged));
public GeoboundingBox Extent
{
get { return GetValue(ExtentProperty) as GeoboundingBox; }
set { SetValue(ExtentProperty, value); }
}
private async static void OnExtentPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var behavior = dependencyObject as ExtentBehavior;
var mapControl = behavior.AssociatedObject as MapControl;
if (!behavior.IsFromEvent)
{
var result = await mapControl.TrySetViewBoundsAsync(behavior.Extent, null, MapAnimationKind.Default);
}
behavior.IsFromEvent = false;
}
private bool IsFromEvent { get; set; }
private void MapLoadingStatusChanged(MapControl sender, object args)
{
if (sender.LoadingStatus == MapLoadingStatus.Loaded)
{
IsFromEvent = true;
Extent = GetBounds(sender);
}
}
private GeoboundingBox GetBounds(MapControl mapControl)
{
// code omitted
}
}