2012-10-19 7 views
6

Ich versuche, die Grundlagen zum Erstellen eines benutzerdefinierten Bereichs in einer WinRT XAML App zu lernen. Ich habe eine angefügte Abhängigkeitseigenschaft definiert und funktioniert wie erwartet, außer dass ich nicht herausfinden kann, wie der Rückruf der Eigenschaft für ein untergeordnetes Element abgerufen wird, um die Anordnung oder das Maß des Containers auszulösen.Wie weiß ein Container, wenn ein Kind InvalidateArrange aufgerufen hat?

Was ist der richtige Weg, damit ein Kind seinen Container wissen lässt, dass arrange und measure erneut aufgerufen werden sollten? In meinem freigeschalteten WPF 4-Buch verwenden sie FrameworkPropertyMetadataOptions.AffectsParentArrange, das scheint jedoch in WinRT nicht verfügbar zu sein.

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 
} 

Antwort

0

Wenn InvalidateArrange allein nicht, dass Sie auch InvalidateMeasure oder UpdateLayout könnten versuchen, nicht funktioniert.

+1

Changed Rückruf InvalidateArrange(), InvalidateMeasure() und UpdateLayout(), aber weder Stützpunkte in ArrangeOverride() noch MeasureOverride() sind getroffen in der Kontainer. – user263619

+0

Vielleicht überprüft es, ob eine der Layouteigenschaften geändert wurde und wenn keine - hat es nicht aufgerufen. Möglicherweise müssen Sie dann einige der Layouteigenschaften ändern, aber dadurch können bestehende Bindungen aufgehoben werden. –

3

Ich bin zu spät zur Party, aber ich ging in die gleiche Richtung und stand vor dem gleichen Problem. Hier ist meine Lösung.

In Ihrem Rückruf rufen Sie InvalidateArrange auf das Kind Element, das Sie Sie Eigentum an:

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

Aber Sie sollten wirklich das Panel ungültig machen, indem Sie Code ändern, so:

public static void OnTopPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) 
{ 
    UIElement panel= VisualTreeHelper.GetParent(source) as UIElement; 
    if(panel != null)  
     panel.InvalidateArrange(); 
} 

Und es sollte funktionieren (hat für mich getan).

+0

Dies sollte als Antwort markiert werden. – Yawar

+0

Ich kann nicht glauben, dass ich gerade den besseren Teil von zwei Tagen damit verbracht habe, das herauszufinden ... Vielen Dank! – Gaet

0

Ich hatte dieses Problem mit einem Kind Kontrolle, die auf der FontSize der übergeordneten Kontrolle abhing. Ich löste das Problem, indem sie den Stapel der Eltern reisen und ungültig zu machen alles:

static MyControl() 
    { 
     // replace base implementation of the dependent property 
     FontSizeProperty.OverrideMetadata(typeof(Scalar), 
      new FrameworkPropertyMetadata(SystemFonts.MessageFontSize, FrameworkPropertyMetadataOptions.Inherits, OnMeasureInvalidated)); 
    } 

    private static void OnMeasureInvalidated(DependencyObject sender, DependencyPropertyChangedEventArgs args) 
    { 
     // recurse over parent stack 
     while (true) 
     { 
      var parent = VisualTreeHelper.GetParent(sender) as UIElement; 
      if (parent == null) return; // break on root element 
      parent.InvalidateMeasure(); 
      sender = parent; 
     } 
    } 
Verwandte Themen