WPF: Изменение размеров круга, сохраняя центральную точку вместо TopLeft?

Я хотел бы изменить размер круга на своем холсте с помощью ползунка. Этот круг может быть перемещен на холсте некоторого материала drag&drop, который я сделал в коде позади, таким образом, его положение не фиксируется.

Я связал значение ползунка с высотой и шириной эллипса. К сожалению, когда я использую ползунок, круг изменен с его верхней левой точкой (на самом деле верхняя левая точка прямоугольника, это находится в), остающийся такой же во время операции.

Я хотел бы изменить размер его с его центральной точкой, являющейся постоянным во время операции. Существует ли простой способ сделать это в XAML? BTW, я уже попробовал 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>
8
задан Jan 6 August 2010 в 12:55
поделиться

4 ответа

Вы можете привязать свои Canvas.Left и Canvas.Top к своей высоте и ширине через ValueConverter.

В частности (править):
Создайте свойство для каждого из Canvas.Left и Canvas.Top и выполните привязку к ним.
Сохраните старые значения для ширины и высоты или старое значение ползунка.
Всякий раз, когда ползунок изменяется, получите инкрементное изменение «dx» путем вычитания сохраненного значения.
(Не забудьте обновить сохраненное значение ...)
Добавьте dx к свойствам ширины и высоты.
И, как сказал Уилл, добавьте dx / 2 * -1 к свойствам Canvas.Left и Canvas.Top.

Есть ли в этом смысл?

4
ответ дан 5 December 2019 в 18:55
поделиться

Поскольку вы используете Canvas, местоположение элемента является местоположением. Если вы хотите, чтобы положение сверху, слева изменилось, вам нужно сделать это самостоятельно. Если вы использовали другой тип панели, например сетку, вы могли бы изменить выравнивание своего эллипса, чтобы разместить его в том же относительном месте независимо от размера. Вы можете получить этот эффект, добавив сетку внутри вашего AdornerDecorator и центрируя Ellipse, но вам также нужно будет установить AdornerDecorator или Grid на фиксированный размер, потому что они не будут растягиваться на холсте.

Лучшим решением, которое вы могли бы использовать, было бы применение ScaleTransform к свойству RenderTransform с RenderTransformOrigin, равным 0,5,0,5. Вы сказали, что у вас проблемы с ScaleTransform, но не в чем проблема.

2
ответ дан 5 December 2019 в 18:55
поделиться

Оберните ваш эллипс в сетку максимального размера. Пока он меньше, эллипс будет центрирован в сетке:

    <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>

Вам может потребоваться настроить логику перетаскивания, чтобы обрабатывать перетаскивание сетки, а не самого эллипса.

1
ответ дан 5 December 2019 в 18:55
поделиться

Проблема в том, что вы используете СЛАЙДЕР для регулировки ширины и высоты. Ширина и высота не рассчитываются для 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
ответ дан 5 December 2019 в 18:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: