WPF: как сделать (0,0) в центре внутри холста

У холста WPF есть система координат, начинающаяся с (0,0) в левом верхнем углу элемента управления.

Например, установка следующего параметра заставит мой элемент управления появиться в верхнем левом углу:

<Control Canvas.Left="0" Canvas.Top="0">

Как я могу изменить его на стандартные декартовы координаты?

В принципе:

  • (0,0) в центре
  • flip Y

Я заметил этот пост, но он не говорит о переводе системы координат. Я попытался добавить TranslateTransform, но я не могу заставить его работать.

Ответы

Ответ 1

Лучше всего написать пользовательский холст, в котором вы можете написать ArrangeOverride таким образом, чтобы в качестве центра он занимал 0,0.

Обновление: я дал еще один комментарий в следующем ответе (@decasteljau). Я не рекомендую выводить из Canvas. Вы можете получить из Panel и добавить два свойства Attached Dependancy Top и Left и поместить тот же код, который вы вставили выше. Также не нужен конструктор с LayoutTransform в нем, и не используйте какое-либо преобразование на код панели, используя надлежащую меру и организуйте на основе желаемого размера панели. Таким образом, вы также можете добиться хорошего поведения для изменения контента. Холст не динамически позиционирует элементы при изменении размера холста.

Ответ 2

Нет необходимости создавать настраиваемую панель. Canvas будет работать отлично. Просто оберните его внутри другого элемента управления (например, границы), центрируйте его, придайте ему нулевой размер и переверните его с помощью RenderTransform:

<Border>
  <Canvas HorizontalAlignment="Center" VerticalAlignment="Center"
          Width="0" Height="0"
          RenderTransform="1 0 0 -1 0 0">
    ...
  </Canvas>
</Border>

Вы можете сделать это, и все в холсте все равно появится, кроме (0,0) будет находиться в центре содержащего элемента управления (в этом случае центр границы) и + Y будут вместо вниз.

Опять же, не требуется для создания пользовательской панели для этого.

Ответ 3

Это было очень легко сделать. Я посмотрел оригинальный код Canvas с использованием .NET Reflector и заметил, что реализация на самом деле очень проста. Единственное, что нужно было, это переопределить функцию ArrangeOverride(...)

public class CartesianCanvas : Canvas
{
    public CartesianCanvas()
    {
        LayoutTransform = new ScaleTransform() { ScaleX = 1, ScaleY = -1 };
    }
    protected override Size ArrangeOverride( Size arrangeSize )
    {
        Point middle = new Point( arrangeSize.Width / 2, arrangeSize.Height / 2 );

        foreach( UIElement element in base.InternalChildren )
        {
            if( element == null )
            {
                continue;
            }
            double x = 0.0;
            double y = 0.0;
            double left = GetLeft( element );
            if( !double.IsNaN( left ) )
            {
                x = left;
            }

            double top = GetTop( element );
            if( !double.IsNaN( top ) )
            {
                y = top;
            }

            element.Arrange( new Rect( new Point( middle.X + x, middle.Y + y ), element.DesiredSize ) );
        }
        return arrangeSize;
    }
}

Ответ 4

Вы можете просто изменить Origin с помощью RenderTransformOrigin.

    <Canvas Width="Auto" Height="Auto"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            RenderTransformOrigin="0.5,0.5">
        <Canvas.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleY="-1" ScaleX="1" />
            </TransformGroup>
        </Canvas.RenderTransform>
    </Canvas>