WPF:如何调整圆的大小,保持中心点而不是左上角?

8
我想用滑动条调整画布上圆的大小。这个圆可以通过一些拖放操作在代码中移动,因此它的位置不是固定的。
我已经将滑动条的值绑定到椭圆的高度和宽度上。然而,当我使用滑动条时,圆会被重新调整大小,但其左上角点(实际上是它所在矩形的左上角点)在操作期间保持不变。
我希望在操作期间以其中心点为常量来调整它的大小。在XAML中有没有简单的方法可以做到这一点?顺便说一句,我已经尝试过ScaleTransform,但它并没有完全达到我的要求。
谢谢!:-)
Jan
<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个回答

4
你可以通过使用ValueConverter将Canvas.Left和Canvas.Top绑定到你的高度和宽度上。
具体来说(编辑): 为Canvas.Left和Canvas.Top分别创建一个属性并绑定到它们。 存储宽度和高度或旧滑块值的旧值。 每当滑块更改时,通过减去存储的值获取增量变化“dx”。 (不要忘记更新存储的值...) 将dx添加到宽度和高度属性中。 正如威尔所说,将dx/2*-1添加到Canvas.Left和Canvas.Top属性中。
这样讲清楚了吗?

谢谢你的回答!它让我知道我的问题是不完整的;-) 圆圈在画布上的位置不固定,这就是为什么我找不到使用ValueConverter的方法... - Jan
等等,这个方法可行。你需要一个值转换器来执行 value/2*-1 - user1228
嗨,马丁!谢谢 - 我打算在周三测试一下并回报 :) - Jan
我不理解这个解决方案,你能详细地、一步一步地解释一下吗? - Ewerton
@Ewerton 你学到哪里了?有什么不理解的地方吗? - Martin Hennings

3
问题在于您正在使用滑块来调整宽度和高度。宽度和高度不是围绕RenderTransformOrigin计算的;只有RenderTransforms使用该值。
这是一个已校正的版本(等一下,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>

谢谢Will!不过,我确实关心边框;-)所以,是的,我已经尝试了ScaleTransform,但这也会影响我的Adorner(为了简洁起见,在此省略了)...还有其他想法吗? :-) - Jan
@Jan 难办啊。在这种情况下,你可能需要创建一个自定义控件。原因是你无法绑定到Canvas.Left和Canvas.Top。如果可以的话,你可以在绑定上使用转换器来获取值(比如滑块的值为10),将其取反并除以2。这样就可以使圆的原点与宽度和高度的增加相匹配。但由于你无法这样做,所以你可以创建一个自定义控件,执行这个计算,并相应地更新椭圆。 - user1228
@Jan添加了一个新的解决方案——只需将椭圆形放入网格中,问题就解决了。 - user1228
@Jan,你的问题似乎没有(如果我没记错的话)提供关于如何在画布上移动椭圆的足够信息。但是,如果您需要这样做,您将不得不移动网格以在画布上移动椭圆。您甚至可以将其移出画布。例如,如果您的网格大小为100x100,并且您需要将椭圆居中于画布上的0,0位置,则网格应从-50,-50开始。 - user1228
嗨,威尔!是的,抱歉,我忘记先提到这个要求,后来稍微编辑了一下... - Jan
显示剩余4条评论

2
由于您正在使用Canvas,元素的位置就是该位置。如果您希望更改顶部和左侧位置,则需要自己完成。如果您使用另一种Panel类型,例如Grid,则可以更改椭圆的对齐方式以使其在任何大小下处于相同的相对位置。您可以通过在AdornerDecorator中添加一个Grid并将椭圆居中来实现该效果,但您还需要将AdornerDecorator或Grid设置为固定大小,因为它们不会在Canvas中拉伸。
最好的解决方案是应用于RenderTransform属性的ScaleTransform,并将RenderTransformOrigin设置为0.5,0.5。您说您有ScaleTransform的问题,但未说明问题所在。

ScaleTransform基本上将我拥有的一切都放大了,因此我的Adorner(为了简洁起见,我在这里没有包含代码)随着缩放变得更大,并且描边厚度(边框大小)也增加了。然而,我只想调整圆形本身的大小,使描边厚度和Adorner大小保持不变... - Jan
1
从你的回应中,看起来你想要为您的椭圆设置一个变量中心点而不是Top, Left。您可以通过在AdornerDecorator上添加一个绑定器和转换器来实现此效果,将其绑定到Margin上,并将Margin设置为(-ActualWidth/2,-ActualHeight/2,0,0)。这实际上会将元素向上和向左移动以居中显示您设置的Top, Left点。 - John Bowen
嗨,约翰!听起来很有趣 - 谢谢你的解决方案 :) 如果马丁使用Canvas.Top/.Left绑定的解决方案对我不起作用,这可能非常有帮助... - Jan

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>

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


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接