How does a container know when a child called InvalidateArrange?

I am trying to learn the basics of creating a custom panel in a WinRT XAML application. I have defined the attached dependency property, and it works as expected, except that I cannot figure out how to get the property callback for the child to trigger the location or dimension of the container.

How can a child let this container know that the arrangement and measurement should be called again? In my WPF 4 expandable book, they use FrameworkPropertyMetadataOptions.AffectsParentArrange, but this does not seem to be available in 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 } 
+6
source share
3 answers

I'm late for the party, but I went in the same direction and ran into the same problem. Here is my solution.

In your callback, you call InvalidateArrange on the child element to which you bound the property:

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

But you really have to invalidate the panel by changing your code like this:

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

And it should work (done for me).

+3
source

If InvalidateArrange is not working, you can also try InvalidateMeasure or UpdateLayout.

0
source

I had this problem with a child control that depended on the FontSize parent control. I solved the problem by traveling along the stack of parents and not recognizing anything invalid:

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

Source: https://habr.com/ru/post/928153/


All Articles