调整画布项目大小 [英] Resizing canvas items
问题描述
我试图创建画布,当画布本身调整大小时,调整其大小。所以我创建我自己的类继承自canvas和覆盖方法ArrangeOverride,其中我设置的位置和大小为所有在画布中定义的孩子。
一切看起来不错,但是当我调整应用程序的窗口时,项目未调整为正确的大小或位置。
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 where I set positions and sizes for all children defined in canvas. Everything looks fine but when I resize window of the application, items weren't resized to correct size or position.
这是一个简化的示例,将其元素粘贴到画布的右边框:
This is simplified example, which tries to snap its elements to right border of canvas:
Xaml代码:
<Border BorderBrush="Black" BorderThickness="1" Margin="10" SnapsToDevicePixels="True">
<l:CustomPanel>
<Rectangle Fill="Red" />
<Button>a</Button>
</l:CustomPanel>
</Border>
CustomPanel:
CustomPanel:
public class CustomPanel : Canvas
{
protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
{
var ret = base.ArrangeOverride(arrangeSize);
var top = 0;
foreach(UIElement child in Children)
{
Canvas.SetLeft(child, arrangeSize.Width - 20.0);
child.SetValue(WidthProperty, arrangeSize.Width - Canvas.GetLeft(child));
Canvas.SetTop(child, top);
child.SetValue(HeightProperty, 20.0);
top += 30;
}
return ret;
}
}
当我改变窗口的宽度时,喜欢这张图片:
When I change width of the window, sometimes canvas looks like on this image:
然后,如果我改变窗口的高度,项目移动到正确的位置
And then, if I change height of the window, items move to correct position
我做错了什么?
我试图将SnapsToDevicePixels设置为True,它不适合我。 : - (
What am I doing wrong? I tried to set SnapsToDevicePixels to True and it doesn't work for me. :-(
推荐答案
您的自定义面板应来自 Panel
Canvas
并覆盖 MeasureOverride
和 ArrangeOverride
应该为子元素布局定义其自己的附加属性,如四个属性 RelativeX
, RelativeY
, RelativeWidth
和 RelativeHeight
如下所示。
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.
<local:RelativeLayoutPanel>
<Rectangle Fill="Red"
local:RelativeLayoutPanel.RelativeX="0.2"
local:RelativeLayoutPanel.RelativeY="0.1"
local:RelativeLayoutPanel.RelativeWidth="0.6"
local:RelativeLayoutPanel.RelativeHeight="0.8"/>
</local:RelativeLayoutPanel>
以下是实施:
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;
}
}
如果你不需要四个布局属性可以独立绑定或通过样式设置等设置。你也许可以用 Rect
类型的单个附加属性替换它们:
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
:
<local:RelativeLayoutPanel>
<Rectangle Fill="Red" local:RelativeLayoutPanel.RelativeRect="0.2,0.1,0.6,0.8"/>
</local:RelativeLayoutPanel>
这个更短的实现:
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;
}
}
这篇关于调整画布项目大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!