2012-10-19 3 views
6

Tôi đang cố gắng tìm hiểu các khái niệm cơ bản về việc tạo bảng tùy chỉnh trong ứng dụng WinRT XAML. Tôi đã xác định một thuộc tính phụ thuộc đính kèm và nó hoạt động như mong đợi, ngoại trừ tôi không thể tìm ra cách để gọi lại của tài sản cho một phần tử con để kích hoạt sắp xếp hoặc đo lường của vùng chứa.Làm thế nào để một container biết khi nào một đứa trẻ đã gọi là InvalidateArrange?

Cách thích hợp để trẻ có thể cho phép thùng chứa biết rằng sắp xếp và đo lường phải được gọi lại? Trong cuốn sách WPF 4 của tôi, chúng sử dụng FrameworkPropertyMetadataOptions.AffectsParentArrange nhưng nó dường như không có sẵn trong 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 
} 

Trả lời

0

Nếu InvalidateArrange một mình không hoạt động, bạn cũng có thể thử InvalidateMeasure hoặc UpdateLayout.

+1

callback được đổi InvalidateArrange(), InvalidateMeasure(), và UpdateLayout() nhưng không breakpoint trong ArrangeOverride() cũng không MeasureOverride() được nhấn trong thùng chứa. – user263619

+0

Có lẽ nó sẽ kiểm tra xem bất kỳ thuộc tính layout nào đã thay đổi và nếu không có thuộc tính layout nào - nó không gọi nó. Bạn có thể cần phải thay đổi một số thuộc tính bố cục, nhưng điều đó có thể phá vỡ các ràng buộc hiện có. –

3

Tôi đến muộn bên, nhưng tôi đã đi theo cùng một hướng và phải đối mặt với cùng một vấn đề. Đây là giải pháp của tôi.

Trong callback của bạn, bạn gọi InvalidateArrange trên phần tử con bạn kèm theo bạn sở hữu tới:

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

Nhưng bạn thực sự cần vô hiệu hóa bảng điều khiển, bằng cách thay đổi bạn mã như vậy:

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

Và nó nên làm việc (đã làm cho tôi).

+0

Điều này sẽ được đánh dấu là câu trả lời. – Yawar

+0

Tôi không thể tin rằng tôi chỉ dành phần tốt hơn trong hai ngày cố gắng tìm ra điều này ... Cảm ơn rất nhiều! – Gaet

0

Tôi gặp sự cố này với điều khiển con phụ thuộc vào số FontSize của kiểm soát gốc. Tôi giải quyết vấn đề bằng cách đi du lịch lên stack của cha mẹ và làm vô hiệu tất cả mọi thứ:

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