Я хотел бы изменить размер круга на своем холсте с помощью ползунка. Этот круг может быть перемещен на холсте некоторого материала 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>
Вы можете привязать свои Canvas.Left и Canvas.Top к своей высоте и ширине через ValueConverter.
В частности (править):
Создайте свойство для каждого из Canvas.Left и Canvas.Top и выполните привязку к ним.
Сохраните старые значения для ширины и высоты или старое значение ползунка.
Всякий раз, когда ползунок изменяется, получите инкрементное изменение «dx» путем вычитания сохраненного значения.
(Не забудьте обновить сохраненное значение ...)
Добавьте dx к свойствам ширины и высоты.
И, как сказал Уилл, добавьте dx / 2 * -1 к свойствам Canvas.Left и Canvas.Top.
Есть ли в этом смысл?
Поскольку вы используете Canvas, местоположение элемента является местоположением. Если вы хотите, чтобы положение сверху, слева изменилось, вам нужно сделать это самостоятельно. Если вы использовали другой тип панели, например сетку, вы могли бы изменить выравнивание своего эллипса, чтобы разместить его в том же относительном месте независимо от размера. Вы можете получить этот эффект, добавив сетку внутри вашего AdornerDecorator и центрируя Ellipse, но вам также нужно будет установить AdornerDecorator или Grid на фиксированный размер, потому что они не будут растягиваться на холсте.
Лучшим решением, которое вы могли бы использовать, было бы применение ScaleTransform к свойству RenderTransform с RenderTransformOrigin, равным 0,5,0,5. Вы сказали, что у вас проблемы с ScaleTransform, но не в чем проблема.
Оберните ваш эллипс в сетку максимального размера. Пока он меньше, эллипс будет центрирован в сетке:
<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>
Вам может потребоваться настроить логику перетаскивания, чтобы обрабатывать перетаскивание сетки, а не самого эллипса.
Проблема в том, что вы используете СЛАЙДЕР для регулировки ширины и высоты. Ширина и высота не рассчитываются для 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>