Resizing canvas items

前端 未结 3 1762
Happy的楠姐
Happy的楠姐 2021-01-24 15:07

I\'m trying to create canvas which resizes its children when canvas itself is resized. So I create my own class which inherits from canvas and overrides method ArrangeOverride w

3条回答
  •  既然无缘
    2021-01-24 15:26

    Your custom panel should derive from Panel instead of Canvas and override the MeasureOverride and ArrangeOverride methods. Moreover it should define its own attached properties for child element layout, like the four properties RelativeX, RelativeY, RelativeWidth and RelativeHeight shown below.

    It would be used in XAML like this:

    
        
    
    

    Here's the implementation:

    public class RelativeLayoutPanel: Panel
    {
        public static readonly DependencyProperty RelativeXProperty = DependencyProperty.RegisterAttached(
            "RelativeX", typeof(double), typeof(RelativeLayoutPanel),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
    
        public static readonly DependencyProperty RelativeYProperty = DependencyProperty.RegisterAttached(
            "RelativeY", typeof(double), typeof(RelativeLayoutPanel),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
    
        public static readonly DependencyProperty RelativeWidthProperty = DependencyProperty.RegisterAttached(
            "RelativeWidth", typeof(double), typeof(RelativeLayoutPanel),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
    
        public static readonly DependencyProperty RelativeHeightProperty = DependencyProperty.RegisterAttached(
            "RelativeHeight", typeof(double), typeof(RelativeLayoutPanel),
            new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
    
        public static double GetRelativeX(UIElement element)
        {
            return (double)element.GetValue(RelativeXProperty);
        }
    
        public static void SetRelativeX(UIElement element, double value)
        {
            element.SetValue(RelativeXProperty, value);
        }
    
        public static double GetRelativeY(UIElement element)
        {
            return (double)element.GetValue(RelativeYProperty);
        }
    
        public static void SetRelativeY(UIElement element, double value)
        {
            element.SetValue(RelativeYProperty, value);
        }
    
        public static double GetRelativeWidth(UIElement element)
        {
            return (double)element.GetValue(RelativeWidthProperty);
        }
    
        public static void SetRelativeWidth(UIElement element, double value)
        {
            element.SetValue(RelativeWidthProperty, value);
        }
    
        public static double GetRelativeHeight(UIElement element)
        {
            return (double)element.GetValue(RelativeHeightProperty);
        }
    
        public static void SetRelativeHeight(UIElement element, double value)
        {
            element.SetValue(RelativeHeightProperty, value);
        }
    
        protected override Size MeasureOverride(Size availableSize)
        {
            availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
    
            foreach (UIElement element in InternalChildren)
            {
                element.Measure(availableSize);
            }
    
            return new Size();
        }
    
        protected override Size ArrangeOverride(Size finalSize)
        {
            foreach (UIElement element in InternalChildren)
            {
                element.Arrange(new Rect(
                    GetRelativeX(element) * finalSize.Width,
                    GetRelativeY(element) * finalSize.Height,
                    GetRelativeWidth(element) * finalSize.Width,
                    GetRelativeHeight(element) * finalSize.Height));
            }
    
            return finalSize;
        }
    }
    

    If you don't need the four layout properties to be independently bindable or settable by style setters etc. you could perhaps replace them by a single attached property of type Rect:

    
        
    
    

    with this much shorter implementation:

    public class RelativeLayoutPanel: Panel
    {
        public static readonly DependencyProperty RelativeRectProperty = DependencyProperty.RegisterAttached(
            "RelativeRect", typeof(Rect), typeof(RelativeLayoutPanel),
            new FrameworkPropertyMetadata(new Rect(), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
    
        public static Rect GetRelativeRect(UIElement element)
        {
            return (Rect)element.GetValue(RelativeRectProperty);
        }
    
        public static void SetRelativeRect(UIElement element, Rect value)
        {
            element.SetValue(RelativeRectProperty, value);
        }
    
        protected override Size MeasureOverride(Size availableSize)
        {
            availableSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
    
            foreach (UIElement element in InternalChildren)
            {
                element.Measure(availableSize);
            }
    
            return new Size();
        }
    
        protected override Size ArrangeOverride(Size finalSize)
        {
            foreach (UIElement element in InternalChildren)
            {
                var rect = GetRelativeRect(element);
    
                element.Arrange(new Rect(
                    rect.X * finalSize.Width,
                    rect.Y * finalSize.Height,
                    rect.Width * finalSize.Width,
                    rect.Height * finalSize.Height));
            }
    
            return finalSize;
        }
    }
    

提交回复
热议问题