Как сделать преобразование местоположения UIElement постоянным?

При поиске способов перетаскивания UIElement в WPF я наткнулся на некоторый код и экспериментировал с ним. Когда элемент нажат, он хорошо следует за мышью, но при последующем событии перетаскивания элемент сбрасывается в исходное положение.

Настройка xaml: очень просто, просто именованный Canvas с самым оригинальным именем и элемент, в данном случае сетка, с именем Tile1.

<Grid>
         <Canvas x:Name="Canvas" Width="200" Height="300" Background="LightGray">
            <Grid x:Name="Tile1">
                <Border BorderBrush="Black" BorderThickness="1" Background="White">
                    <Control Width="25" Height="25"/>
                </Border>
            </Grid>
        </Canvas>
</Grid>

некоторый код:

public TranslateTransform transPoint;
public Point originPoint;

public MainWindow()
        {
            InitializeComponent();
            Tile1.MouseLeftButtonDown += Tile1_MouseLeftButtonDown;
            Tile1.MouseLeftButtonUp += Tile1_MouseLeftButtonUp;
            Tile1.MouseMove += Tile1_MouseMove;
        }

        private void Tile1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var myLocation = e.GetPosition(Canvas);
            originPoint = new Point(myLocation.X, myLocation.Y);
            transPoint = new TranslateTransform(originPoint.X, originPoint.Y);
        }

        private void Tile1_MouseMove(object sender, MouseEventArgs e)
        {
            var mouseLocation = e.GetPosition(Canvas);

            if (e.LeftButton == MouseButtonState.Pressed)
            {
                transPoint.X = (mouseLocation.X - originPoint.X);
                transPoint.Y = (mouseLocation.Y - originPoint.Y);
                Tile1.RenderTransform = transPoint;
            }
        }

        private void Tile1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var mouseLocationOnCanvas = e.GetPosition(Canvas);
            var mouseLocationOnTile = e.GetPosition(Tile1);

            //attempting to account for offset of mouse on the Tile:
            var newX = mouseLocationOnCanvas.X - mouseLocationOnTile.X;
            var newY = mouseLocationOnCanvas.Y - mouseLocationOnTile.Y;

            Tile1.Margin = new Thickness(newX, newY, 0, 0);
        }

В исходном примере (ссылка добавлена ​​здесь) событие MouseUpEvent даже не использовалось. Без него мой элемент просто сбрасывается в исходное положение на 0,0 при каждом MouseDragEvent. И с ним он будет прыгать повсюду.

Моя мысль заключалась в том, чтобы каким-то образом установить текущую позицию элемента в том месте, где произошло событие MouseUpEvent. Я возился с разными вещами, так как этот конкретный материал для меня довольно новый. Примеры: Tile1.TransformToAncestor(Canvas).Transform(mouseLocation); Я также обнаружил, что в VisualOffset есть нужная мне информация, поэтому она каким-то образом уже сохранена в объекте до сброса, но я не нашел способа получить к ней доступ в какой-либо форме. Tile1.SetValue(VisualOffset.X = ...); или Tile1Grid.GetValue(VisualOffset);

Итак, есть ли способ не сбрасывать позицию элемента после RenderTransform?


person NewInTown    schedule 14.05.2020    source источник
comment
Решит ли мой ответ вашу проблему? если нет, пожалуйста, дайте мне знать, если я могу помочь, улучшив его.   -  person Cfun    schedule 17.05.2020


Ответы (2)


Я не нашел событие MouseLeftButtonDown полезным, поэтому удалил его: я заметил некоторые задержки при перемещении мыши, которые могут раздражать, возможно, событие должно выполняться асинхронно Снижение производительности MouseMove при использовании GetPosition.

 public TranslateTransform transPoint = new TranslateTransform(0, 0);
 public Point originPoint = new Point(0, 0);

public MainWindow()
        {
            InitializeComponent();
            Tile1.MouseLeftButtonUp += Tile1_MouseLeftButtonUp;
            Tile1.MouseMove += Tile1_MouseMove;
        }

private void Tile1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                var mouseLocation = e.GetPosition(Canvas);

                transPoint.X = (mouseLocation.X - originPoint.X);
                transPoint.Y = (mouseLocation.Y - originPoint.Y);
                Tile1.RenderTransform = transPoint;

            }
        }

private void Tile1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
   var mouseLocation = e.GetPosition(Tile1);
   originPoint.X = mouseLocation.X;
   originPoint.Y = mouseLocation.Y;
        }
person Cfun    schedule 14.05.2020
comment
К сожалению, плитка все еще продолжает прыгать. Я был удивлен, что он вообще двигался без использования MouseLeftButtonDown, но, по моему опыту, он менее отзывчив, если его опустить. - person NewInTown; 22.05.2020

RenderTransform кажется ошибочным, но я заставил UIElement оставаться на месте после его перемещения, используя следующее:

private void MovableTile_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        tile.CaptureMouse();
    }

с участием

private void MovableTile_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            var tile = sender as UIElement;
            var mousePosition = e.GetPosition(canvas);
            Canvas.SetLeft(tile, mousePosition.X);
            Canvas.SetTop(tile, mousePosition.Y);
        }
    }

а потом

private void MovableTile_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        tile.ReleaseMouseCapture();
    }

MouseCapture был ключом здесь. :)

person NewInTown    schedule 03.06.2020