WPF: Изменение размера круга, сохранение центральной точки вместо TopLeft? - PullRequest
8 голосов
/ 06 августа 2010

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

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

Я хотел бы изменить его размер с помощьюего центр точка является постоянной во время операции.Есть ли простой способ сделать это в 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 ]

4 голосов
/ 06 августа 2010

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

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

Имеет ли это смысл?

2 голосов
/ 06 августа 2010

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

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

2 голосов
/ 06 августа 2010

Проблема в том, что вы используете слайдер для регулировки ширины и высоты. Ширина и высота не рассчитываются вокруг 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>
1 голос
/ 06 августа 2010

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

    <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 голосов
/ 04 ноября 2012

Я нашел очень простой способ сделать это в простом XAML: установить Margin="-1000000". Подробнее читайте здесь: Расположение элемента внутри холста по его центру (вместо верхнего левого угла) с использованием только XAML в WPF

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...