FramworkElement 安排不放置子 FramworkElement
我有两节课[适用于这个问题]。第一个 XYAxes2
扩展了 FrameworkElement
。它会覆盖 MeasureOverride
和 ArrangeOverride
,试图将其唯一的子元素 XAxis
(也扩展了 FrameworkElement
)放置在所需的位置。
XYAxes2
(父级):
Scale XAxis =//...
protected override Size MeasureOverride( Size availableSize ) {
XAxis.Measure( availableSize );
return (Size)availableSize;
}
protected override Size ArrangeOverride( Size finalSize ) {
XAxis.Arrange( new Rect( 50, 50, 100, 200 ) );
return finalSize;
}
Scale
是自定义绘制的组件。 Scale
(子级):
protected override void OnRender( DrawingContext cx ) {
ValidateTicks();
if (Orientation == Orientation.Horizontal) {
cx.DrawLine( Pen, new Point( -.5, .5 ), new Point( ActualWidth - .5, .5 ) );
foreach (double tick in _ticks.Keys) {
double val = ScaleTransformCallback( tick );
double x = -0.5 + (int)((val - MinValue) * ActualWidth / (MaxValue - MinValue));
cx.DrawLine( Pen, new Point( x, .5 ), new Point( x, TickLength - .5 ) );
FormattedText txt = _ticks[tick];
cx.DrawText( txt, new Point( x - txt.Width / 2, TickLength + TextMargin ) );
}
} else {
double Left = maxTextWidth + 2 * TextMargin;
double Right = this.TickLength + Left;
cx.DrawLine( Pen, new Point( Right - .5, +.5 ), new Point( Right - .5, ActualHeight + .5 ) );
foreach (double tick in _ticks.Keys) {
double val = ScaleTransformCallback( tick );
double y = -0.5 + ActualHeight - (int)((val - MinValue) * ActualHeight / (MaxValue - MinValue));
cx.DrawLine( Pen, new Point( Right - .5, y ), new Point( Left - .5, y ) );
FormattedText txt = _ticks[tick];
cx.DrawText( txt, new Point( Left - txt.Width - TextMargin, y - txt.Height / 2 ) );
}
}
}
调试时,该函数中的ActualWidth
始终是父级的宽度,而不是ArrangeOverride
设置的宽度,100。然而,子对象被剪切到由 ArrangeOverride
指定的区域。
我在这些功能之一中做错了什么吗?
编辑:通过将XAxis.Measure(100,200)
插入到ArrangeOverride
中,问题显然已得到解决。当然,不必在每次排列失效时都调用 Measure
(这意味着 InvalidateArrange
需要隐式调用 InvalidateMeasure
)。谁能解释一下这背后的原因吗?
有谁知道 DesiredSize
和 ActualWidth/Height
实际设置在哪里(显然它们不是由我的代码设置的)?
I have two classes [applicable to this question]. The first, XYAxes2
, extends FrameworkElement
. It overrides MeasureOverride
and ArrangeOverride
in an attempt to place it's sole child, XAxis
(also extends FrameworkElement
), in the desired position.
XYAxes2
(Parent):
Scale XAxis =//...
protected override Size MeasureOverride( Size availableSize ) {
XAxis.Measure( availableSize );
return (Size)availableSize;
}
protected override Size ArrangeOverride( Size finalSize ) {
XAxis.Arrange( new Rect( 50, 50, 100, 200 ) );
return finalSize;
}
Scale
is a custom drawn component.Scale
(Child):
protected override void OnRender( DrawingContext cx ) {
ValidateTicks();
if (Orientation == Orientation.Horizontal) {
cx.DrawLine( Pen, new Point( -.5, .5 ), new Point( ActualWidth - .5, .5 ) );
foreach (double tick in _ticks.Keys) {
double val = ScaleTransformCallback( tick );
double x = -0.5 + (int)((val - MinValue) * ActualWidth / (MaxValue - MinValue));
cx.DrawLine( Pen, new Point( x, .5 ), new Point( x, TickLength - .5 ) );
FormattedText txt = _ticks[tick];
cx.DrawText( txt, new Point( x - txt.Width / 2, TickLength + TextMargin ) );
}
} else {
double Left = maxTextWidth + 2 * TextMargin;
double Right = this.TickLength + Left;
cx.DrawLine( Pen, new Point( Right - .5, +.5 ), new Point( Right - .5, ActualHeight + .5 ) );
foreach (double tick in _ticks.Keys) {
double val = ScaleTransformCallback( tick );
double y = -0.5 + ActualHeight - (int)((val - MinValue) * ActualHeight / (MaxValue - MinValue));
cx.DrawLine( Pen, new Point( Right - .5, y ), new Point( Left - .5, y ) );
FormattedText txt = _ticks[tick];
cx.DrawText( txt, new Point( Left - txt.Width - TextMargin, y - txt.Height / 2 ) );
}
}
}
When debugging, ActualWidth
in this function is always the width of the parent rather than the width set by ArrangeOverride
, 100. The child is, however, clipped to the region specified by ArrangeOverride
.
Am I do something wrong in one of these functions?
Edit: By inserting XAxis.Measure(100,200)
into ArrangeOverride
, the problem is apparently fixed. Surely, it shouldn't be necessary to call Measure
everytime the arrangement is invalidated (this would mean InvalidateArrange
would need to implicitly call InvalidateMeasure
). Can anyone shed any light on the causes behind this?
Does anyone know where DesiredSize
and ActualWidth/Height
are actually set (obviously they are not set by my code)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我为此使用的解决方案是在 MeasureOverride 函数中使用多次传递。我不断测量不同的尺寸,直到确定合适的整体尺寸。
通过阅读 .Net 4.0 源代码,可以看出:-
DesiredSize
由UIElement.Measure
函数设置为MeasureOverride
的返回值。ActualWidth
/ActualHeight
(RenderSize
) 由以下设置FrameworkElement.ArrangeCore
是从返回的任何值ArrangeOverride
似乎没有任何错误检查或应用舍入。
我希望这可以帮助其他人。
The solution I have used for this is to use multiple passes in the
MeasureOverride
function. I keep measuring with different sizes until a suitable overall size is determined.By reading through the .Net 4.0 source code, it appears that :-
DesiredSize
is set by theUIElement.Measure
function to be thereturn value of
MeasureOverride
.ActualWidth
/ActualHeight
(RenderSize
) are set byFrameworkElement.ArrangeCore
to be whatever value is returned fromArrangeOverride
There doesn't appear to be any error checking orrounding applied.
I hope this can help other people.