Как контейнер узнает, когда ребенок вызвал InvalidateArrange?

Я пытаюсь изучить основы создания пользовательской панели в приложении WinRT XAML. Я определил вложенное свойство зависимости, и оно работает, как и ожидалось, за исключением того, что я не могу понять, как получить обратный вызов свойства для дочернего элемента, чтобы инициировать расположение или меру контейнера.

Какой правильный способ дать ребенку понять, что его контейнер и меры должны быть вызваны снова? В моей открытой книге WPF 4 они используют FrameworkPropertyMetadataOptions.AffectsParentArrange, но в WinRT этого нет.

public class SimpleCanvas : Panel
{
    #region Variables
    #region Left Property
    public static double GetLeft(UIElement element)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }

        object value = element.GetValue(LeftProperty);
        Type valueType = value.GetType();
        return Convert.ToDouble(value);
    } 

    public static void SetLeft(UIElement element, double value)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }

        element.SetValue(LeftProperty, value);
    }

    public static readonly DependencyProperty LeftProperty =
        DependencyProperty.RegisterAttached("Left", typeof(double), typeof(SimpleCanvas),
        new PropertyMetadata(0, OnLeftPropertyChanged));

    public static void OnLeftPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        UIElement element = (UIElement)source;
        // This doesn't cause ArrangeOverride below to be called
        element.InvalidateArrange();
    }
    #endregion

    #region Top Property
    public static double GetTop(UIElement element)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }

        object value = element.GetValue(TopProperty);
        return (value == null) ? 0 : (double)value;
    }

    public static void SetTop(UIElement element, double value)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }

        element.SetValue(TopProperty, value);
    }

    public static readonly DependencyProperty TopProperty =
        DependencyProperty.RegisterAttached("Top", typeof(double), typeof(SimpleCanvas),
        new PropertyMetadata(0, OnTopPropertyChanged));

    public static void OnTopPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {
        UIElement element = (UIElement)source;
        // This doesn't cause ArrangeOverride below to be called
        element.InvalidateArrange();
    }
    #endregion
    #endregion

    public SimpleCanvas()
    {

    }

    #region Methods
    protected override Size MeasureOverride(Size availableSize)
    {
        foreach (UIElement child in this.Children)
        {
            child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        }

        return new Size(0, 0);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach (UIElement child in this.Children)
        {
            double x = 0;
            double y = 0;

            double left = GetLeft(child);
            double top = GetTop(child);

            if (!double.IsNaN(left))
            {
                x = left;
            }
            if (!double.IsNaN(top))
            {
                y = top;
            }

            child.Arrange(new Rect(new Point(x, y), child.DesiredSize));
        }

        return finalSize;
    }
    #endregion
}

Ответы на вопрос(3)

Ваш ответ на вопрос