行为和双向绑定 - 如何告诉DependencyProperty改变了什么

时间:2015-02-05 05:05:24

标签: windows-phone-8.1 winrt-xaml mvvm-light

我有一个自定义行为,允许我将MapControl范围(边界框)绑定到ViewModel;它的工作原理是,只要地图的LoadingStatusChanged事件触发并设置DependencyProperty的值,就会计算地图的范围。这很好 - 当地图被平移或缩放时,ViewModel中的绑定属性会更新。

但我还希望能够从ViewModel设置地图范围并相应地进行地图平移/缩放。我可以在依赖项属性更改时调用TrySetViewBoundsAsync,但问题是知道依赖项属性更改是源于计算映射的范围,还是来自在ViewModel中设置属性。如果是来自计算范围,它将改变地图的范围,这将再次触发更改的事件,并在无限循环中消失。

我通过添加IsFromEvent属性并在每次响应LoadingStatusChanged事件计算范围时将其设置为true来解决此问题。这可以防止无限循环,但这种方法似乎......关闭。它让我觉得自己很害羞而且不是非常安全。

所以...有更好的方法吗?可以以某种方式设置DP而不会导致PropertyChanged事件触发吗?或者我只是想过这个?

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
    }
}

1 个答案:

答案 0 :(得分:0)

无法询问是谁更改了依赖项属性的值。话虽如此,有一种方法;你可以走回调用堆栈/跟踪。 XAML开发人员多年来一直试图在没有文字字符串的情况下动态提高propertychanged。您的解决方案比使用这样的反射更优雅1000%。

有时我们必须解决解决方案的问题 - 有时解决方案不是基础框架的一部分。您的解决方案可能会感觉有点off,但它解决问题的事实本身就是一种信用。此外,我不认为"线程安全"在这种情况下是一个相关问题,因为所有XAML都在UI线程上。有意义吗?

祝你好运。