容器如何知道孩子何时调用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 } 

我迟到了,但我走的是同一个方向,面临同样的问题。 这是我的解决方案。

在你的回调中,你在你附加属性的子元素上调用InvalidateArrange:

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

但是你应该通过更改代码来使面板无效:

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

它应该工作(对我来说)。

如果单独使用InvalidateArrange不起作用,您还可以尝试InvalidateMeasure或UpdateLayout。

我有一个子控件的问题,它取决于父控件的FontSize 。 我通过向上移动父母的堆栈并使一切无效来解决问题:

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