WPF:调整圆圈大小,保持中心点而不是TopLeft?

时间:2010-08-06 12:44:42

标签: wpf xaml 2d resize centering

我想借助滑块调整画布上的圆圈大小。这个圆圈可以通过我在代码后面做的一些拖放操作在画布上移动,所以它的位置不固定。

我已将滑块的值绑定到椭圆的高度和宽度。不幸的是,当我使用滑块时,圆圈的左上角(实际上是它所在的矩形的左上角)会在操作过程中保持相同的大小。

我希望在操作期间将中心点保持不变来调整大小。在XAML中有一个简单的方法吗?顺便说一下,我已经尝试过ScaleTransform,但它并没有完全按照我的意愿行事。

非常感谢! : - )

<Canvas x:Name="MyCanvas">

    <!-- this is needed for some adorner stuff I do in code behind -->
    <AdornerDecorator Canvas.Left="10"
                      Canvas.Top="10">
        <Ellipse x:Name="myEllipse"
             Height="{Binding Path=Value, ElementName=mySlider}"
             Width="{Binding Path=Value, ElementName=mySlider}"
             Stroke="Aquamarine"
             Fill="AliceBlue"
             RenderTransformOrigin="0.5 0.5">
            <Ellipse.RenderTransform>
                <RotateTransform Angle="{Binding Path=Value, ElementName=myRotationSlider}" />
            </Ellipse.RenderTransform>
        </Ellipse>
    </AdornerDecorator>

    <Slider x:Name="mySlider"
            Maximum="100"
            Minimum="0"
            Width="100"
            Value="10"
            Canvas.Left="150"
            Canvas.Top="10" />
    <Slider x:Name="myRotationSlider"
            Maximum="360"
            Minimum="0"
            Width="100"
            Value="0"
            Canvas.Left="150"
            Canvas.Top="50" />
</Canvas>

5 个答案:

答案 0 :(得分:4)

您可以通过ValueConverter将Canvas.Left和Canvas.Top绑定到高度和宽度。

具体(编辑):
为Canvas.Left和Canvas.Top创建一个属性并绑定到这些属性 存储Width和Heigth的旧值或旧滑块值 每当更改滑块时,通过减去存储的值来获得增量变化“dx” (不要忘记更新储值......)
将dx添加到宽度和高度属性 并且,如Will所说,将dx / 2 * -1添加到Canvas.Left和Canvas.Top属性。

这有意义吗?

答案 1 :(得分:2)

问题是您正在使用SLIDER来调整宽度和高度。 RenderTransformOrigin不计算宽度和高度;只有RenderTransforms才能使用该值。

这是一个更正版本(brb,kaxaml):

<Canvas x:Name="MyCanvas">
<!-- this is needed for some adorner stuff I do in code behind -->
    <AdornerDecorator Canvas.Left="50" Canvas.Top="50">
        <Ellipse
            x:Name="myEllipse"
            Width="10"
            Height="10"
            Fill="AliceBlue"
            RenderTransformOrigin="0.5 0.5"
            Stroke="Aquamarine">
            <Ellipse.RenderTransform>
                <TransformGroup>
                    <RotateTransform Angle="{Binding Path=Value, ElementName=myRotationSlider}"/>
                    <ScaleTransform
                        CenterX=".5"
                        CenterY=".5"
                        ScaleX="{Binding Path=Value, ElementName=mySlider}"
                        ScaleY="{Binding Path=Value, ElementName=mySlider}"/>
                </TransformGroup>
            </Ellipse.RenderTransform>
        </Ellipse>
    </AdornerDecorator>
    <Slider
        x:Name="mySlider"
        Width="100"
        Canvas.Left="150"
        Canvas.Top="10"
        Maximum="10"
        Minimum="0"
        SmallChange=".01"
        Value="1"/>
    <Slider
        x:Name="myRotationSlider"
        Width="100"
        Canvas.Left="150"
        Canvas.Top="50"
        Maximum="360"
        Minimum="0"
        Value="0"/>
</Canvas>

当然,这可能不适合你。为什么?我使用的ScaleTransform不仅可以缩放圆形,还可以缩放边框;随着圆圈变大,边界也会变大。希望你不会关心这个。

此外,在组合变换(在这种情况下缩放然后旋转)时,实现它们按顺序应用,并且可能影响另一个变换的方式。在你的情况下,你不会注意到这一点。但是,如果你正在进行轮换和翻译,那么订单就是相关的。


啊,我在想什么?只需将椭圆固定在网格中(最简单的解决方案,但其他容器可以工作)。在调整椭圆大小时,网格会自动对椭圆进行居中处理。无需任何价值转换器!这是代码:

<Canvas x:Name="MyCanvas">
<!-- this is needed for some adorner stuff I do in code behind -->
    <Grid Width="100" Height="100">
        <AdornerDecorator>
            <Ellipse
                x:Name="myEllipse"
                Width="{Binding Path=Value, ElementName=mySlider}"
                Height="{Binding Path=Value, ElementName=mySlider}"
                Fill="AliceBlue"
                RenderTransformOrigin="0.5 0.5"
                Stroke="Aquamarine">
                <Ellipse.RenderTransform>
                    <RotateTransform Angle="{Binding Path=Value, ElementName=myRotationSlider}"/>
                </Ellipse.RenderTransform>
            </Ellipse>
        </AdornerDecorator>
    </Grid>
    <Slider
        x:Name="mySlider"
        Width="100"
        Canvas.Left="150"
        Canvas.Top="10"
        Maximum="100"
        Minimum="0"
        Value="10"/>
    <Slider
        x:Name="myRotationSlider"
        Width="100"
        Canvas.Left="150"
        Canvas.Top="50"
        Maximum="360"
        Minimum="0"
        Value="0"/>
</Canvas>

答案 2 :(得分:2)

由于您使用的是Canvas,因此元素所在的位置就是位置。如果你想要改变Top,Left位置,你需要自己动手。如果您使用其他面板类型(如网格),则可以更改椭圆的对齐方式,以便将其放在相同的相对位置,无论大小如何。你可以通过在AdornerDecorator中添加一个Grid并使Ellipse居中来获得该效果,但是你还需要将AdornerDecorator或Grid设置为固定大小,因为它们不会在Canvas中拉伸。

您可以使用的最佳解决方案是应用于RenderTransform属性的ScaleTransform,其RenderTransformOrigin为0.5,0.5。你说你有ScaleTransform的问题但不是问题所在。

答案 3 :(得分:1)

将椭圆包裹在最大尺寸的网格中。只要它更小,椭圆将在网格中居中:

    <Grid
        Canvas.Left="10"
        Canvas.Top="10"
        Width="100"
        Height="100">
        <AdornerDecorator>
            <Ellipse x:Name="myEllipse"
             Height="{Binding Path=Value, ElementName=mySlider}"
             Width="{Binding Path=Value, ElementName=mySlider}"
             Stroke="Aquamarine"
             Fill="AliceBlue"
             RenderTransformOrigin="0.5 0.5">
                <Ellipse.RenderTransform>
                    <RotateTransform Angle="{Binding Path=Value, ElementName=myRotationSlider}" />
                </Ellipse.RenderTransform>
            </Ellipse>
        </AdornerDecorator>
    </Grid>

您可能需要调整拖动逻辑来处理拖动网格而不是椭圆本身。

答案 4 :(得分:0)

我在简单的XAML中找到了一种非常简单的方法:设置Margin="-1000000"。在此处阅读更多内容:Positioning an element inside the Canvas by its center (instead of the top left corner) using only XAML in WPF