如何在画布布局中拖动和旋转用户控件

时间:2016-03-12 00:25:29

标签: c# wpf canvas rotation drag

我正在开发一个应用程序,我必须在画布上拖动用户控件。 该用户控件可以在正常位置拖动或以90度,180度,270度的角度旋转。 我在以90或270度的角度拖动用户控件时遇到问题,因为用户控件在鼠标释放时移动到了拖放点。 我尝试使用控件的TransformToVisual方法,但它不能正常工作。 有没有人有什么建议? 如果你需要一些代码或文件问我。 谢谢。

编辑:

这是我的ProdottoCtrl代码:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Shapes;

namespace Libreria_Controlli
{
    /// <summary>
    /// Logica di interazione per ProdottoCtrl.xaml
    /// </summary>
    public partial class ProdottoCtrl : ProdottoCtrlBase
    {
        Rect _rectCanvasDrop1;
        Rect _rectCanvasDrop2;

        bool _isFuoriConfineDrop1;
        bool _isFuoriConfineDrop2;
        bool _isContatto = false;

        public ProdottoCtrl()
        {
            InitializeComponent();
        }

        #region Proprietà User Control

        #region CanvasDrag
        public Canvas CanvasDrag
        {
            get { return (Canvas)GetValue(CanvasDragProperty); }
            set { SetValue(CanvasDragProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CanvasDrag.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CanvasDragProperty =
            DependencyProperty.Register("CanvasDrag", typeof(Canvas), typeof(ProdottoCtrl));
        #endregion

        #region CanvasDrop1

        public CanvasDropCtrl CanvasDrop1
        {
            get { return (CanvasDropCtrl)GetValue(CanvasDrop1Property); }
            set { SetValue(CanvasDrop1Property, value); }
        }

        // Using a DependencyProperty as the backing store for CanvasDrop1.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CanvasDrop1Property =
            DependencyProperty.Register("CanvasDrop1", typeof(CanvasDropCtrl), typeof(ProdottoCtrl));

        #endregion

        #region CanvasDrop2
        public CanvasDropCtrl CanvasDrop2
        {
            get { return (CanvasDropCtrl)GetValue(CanvasDrop2Property); }
            set { SetValue(CanvasDrop2Property, value); }
        }

        // Using a DependencyProperty as the backing store for CanvasDrop2.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CanvasDrop2Property =
            DependencyProperty.Register("CanvasDrop2", typeof(CanvasDropCtrl), typeof(ProdottoCtrl));
        #endregion

        #endregion

        #region Drag handlers
        private void RettangoloProdotto_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _posizioneMouseIniziale= e.GetPosition(TopWindow);

            // DA MUOVERE
            _rectCanvasDrop1 = CanvasDrop1.Canvas.TransformToVisual(TopWindow).TransformBounds(new Rect(0, 0, CanvasDrop1.ActualWidth, CanvasDrop1.ActualHeight));
            _rectCanvasDrop2 = CanvasDrop2.Canvas.TransformToVisual(TopWindow).TransformBounds(new Rect(0, 0, CanvasDrop2.ActualWidth, CanvasDrop2.ActualHeight));

            _isDrag = true;
            e.Handled = true;
        }

        private void RettangoloProdotto_MouseMove(object sender, MouseEventArgs e)
        {
            if(_isDrag)
            {
                if(IsMinimaDistanzaDrag(e.GetPosition(TopWindow)))
                {
                    if(_rettangoloOutline == null)
                    {

                        _rettangoloOutline = new Rectangle();
                        _rettangoloOutline.Width = RettangoloProdotto.Width;
                        _rettangoloOutline.Height = RettangoloProdotto.Height;
                        _rettangoloOutline.Fill = RettangoloProdotto.Fill;
                        _rettangoloOutline.RenderTransform = GridMain.RenderTransform;
                        _rettangoloOutline.Opacity = 0.8;


                        CanvasDrag.Children.Add(_rettangoloOutline);

                        TopWindow.MouseLeftButtonUp += TopWindow_MouseLeftButtonUp;
                        TopWindow.MouseMove += TopWindow_MouseMove;
                    }
                }
            }
        }

        private void TopWindow_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_isDrag || _rettangoloOutline == null)
                return;

            #region Offset rotazione            
            if (Rotazione == 0)
            {
                delta.X = e.GetPosition(CanvasDrag).X - _rectOutline.Width / 2;
                delta.Y = e.GetPosition(CanvasDrag).Y - _rectOutline.Height / 2;
            }
            else if (Rotazione == 90)
            {
                delta.X = e.GetPosition(CanvasDrag).X + _rectOutline.Width / 2;
                delta.Y = e.GetPosition(CanvasDrag).Y - _rectOutline.Height / 2;
            }
            else if (Rotazione == 180)
            {
                delta.X = e.GetPosition(CanvasDrag).X + _rectOutline.Width / 2;
                delta.Y = e.GetPosition(CanvasDrag).Y + _rectOutline.Height / 2;
            }
            else if (Rotazione == 270)
            {
                delta.X = e.GetPosition(CanvasDrag).X - _rectOutline.Width / 2;
                delta.Y = e.GetPosition(CanvasDrag).Y + _rectOutline.Height / 2;
            } 
            #endregion

            Canvas.SetLeft(_rettangoloOutline, delta.X);
            Canvas.SetTop(_rettangoloOutline, delta.Y);

            _rectOutline = _rettangoloOutline.TransformToVisual(TopWindow).TransformBounds(new Rect(0, 0, _rettangoloOutline.Width, _rettangoloOutline.Height));

            _isFuoriConfineDrop1 = IsFuoriConfine(_rectCanvasDrop1);
            _isFuoriConfineDrop2 = IsFuoriConfine(_rectCanvasDrop2);
            _isContatto = IsContatto(); // VErificare velocità con molti pacchi

            if (_isFuoriConfineDrop1)
                Mouse.OverrideCursor = Cursors.No;
            else
                Mouse.OverrideCursor = null;
        }

        private void TopWindow_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            Mouse.OverrideCursor = null;
            e.Handled = true;

            if (!_isDrag)
                return;           

            TopWindow.MouseLeftButtonUp -= TopWindow_MouseLeftButtonUp;
            TopWindow.MouseMove -= TopWindow_MouseMove;

            // Il prodotto è fuori dai confini, avverto l'utente
            if (_isFuoriConfineDrop1 && _isFuoriConfineDrop2)
            {
                // Avverto  l'utente con un avviso visuale (messageBox o meglio segnali sullo
                // User control
            }
            else if(!_isFuoriConfineDrop1) // Sono nel primo CanvasDrop
            {
                if(_isContatto)
                {
                    // Avverto utente del contatto

                }
                else
                {

                    Point p = _rettangoloOutline.TranslatePoint(new Point(0, 0), CanvasDrop1.Canvas);

                    ProdottoDropCtrl prodottoDrop = CreaProdottoDrop();
                    CanvasDrop1.Canvas.Children.Add(prodottoDrop);

                    Point pointSnap = SnapToGrid(new Point(p.X, p.Y));
                    Canvas.SetLeft(prodottoDrop, pointSnap.X );
                    Canvas.SetTop(prodottoDrop, pointSnap.Y);
                }
            }


            if (_rettangoloOutline != null)
            {
                CanvasDrag.Children.Remove(_rettangoloOutline);
                _rettangoloOutline = null;
            }
            _isDrag = false;

            Console.WriteLine("pallet1_Interno {0} - pallet2_Interno {1} - Contatto {2}", !_isFuoriConfineDrop1, !_isFuoriConfineDrop2, _isContatto);            

        }
        #endregion

        private bool IsContatto()
        {
            CanvasDropCtrl canvasDrop = null;

            if (_isFuoriConfineDrop1 && _isFuoriConfineDrop2)
                return false;

            // Sono nel primo pallet
            if (_isFuoriConfineDrop2)
                canvasDrop = CanvasDrop1;
            else // Sono nel secondo pallet
                canvasDrop = CanvasDrop2;

            foreach(var prodotto in canvasDrop.Canvas.Children)
            {
                ProdottoCtrlBase prodottoDrop = prodotto as ProdottoCtrlBase;

                if (this.Equals(prodottoDrop) || prodottoDrop == null)
                    continue;

                Rect rectProdottoDrop = prodottoDrop.TransformToVisual(TopWindow).TransformBounds(new Rect(0, 0, prodottoDrop.Lunghezza, prodottoDrop.Profondita));

                // Contatto - UPDATE: contatto in un solo punto ???
                if (rectProdottoDrop.IntersectsWith(_rectOutline))
                    return true;
            }

            return false;
        }

        private ProdottoDropCtrl CreaProdottoDrop()
        {
            ProdottoDropCtrl prodottoDrop = new ProdottoDropCtrl();
            prodottoDrop.Altezza = Altezza;
            prodottoDrop.Lunghezza = Lunghezza;
            prodottoDrop.Profondita = Profondita;
            prodottoDrop.Rotazione = Rotazione;
            prodottoDrop.GridSize = GridSize;

            prodottoDrop.TopWindow = TopWindow;
            if (!_isFuoriConfineDrop1)
            {
                prodottoDrop.CanvasDrop = CanvasDrop1;
                prodottoDrop.NumeroProdotto = NumeroProdottiCanvas(CanvasDrop1) + 1;
            }
            else
            {
                prodottoDrop.CanvasDrop = CanvasDrop2;
                prodottoDrop.NumeroProdotto = NumeroProdottiCanvas(CanvasDrop2) + 1;
            }            

            return prodottoDrop;
        }

        private int NumeroProdottiCanvas(CanvasDropCtrl canvasDrop)
        {
            int numeroProdotti = 0;

            foreach (var item in canvasDrop.Canvas.Children)
            {
                if (item is ProdottoDropCtrl)
                    numeroProdotti++;
            }

            return numeroProdotti;

        }
    }
}

ProdottoCtrl.xaml:

<local:ProdottoCtrlBase x:Class="Libreria_Controlli.ProdottoCtrl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Libreria_Controlli"
             mc:Ignorable="d" 
             x:Name="UsrCtrl"
             Height="{Binding ElementName=UsrCtrl, Path=Profondita}"
             Width="{Binding ElementName=UsrCtrl, Path=Lunghezza}"
             Focusable="True" >

    <Grid Name="GridMain" RenderTransformOrigin="0.5,0.5"
          Height="{Binding ElementName=UsrCtrl, Path=Profondita}"
          Width="{Binding ElementName=UsrCtrl, Path=Lunghezza}">

        <Grid.RenderTransform>
            <RotateTransform Angle="{Binding ElementName=UsrCtrl, Path=Rotazione}" />
        </Grid.RenderTransform>

        <Grid.RowDefinitions>
            <RowDefinition Height="10" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <Rectangle Grid.Row="0" Name="RettangoloEtichetta" Margin="5,0" Width="50" Height="5" Fill="White" Panel.ZIndex="100" VerticalAlignment="Bottom"/>

        <Rectangle Name="RettangoloProdotto"
                   Height="{Binding ElementName=UsrCtrl, Path=Profondita}"
                   Width="{Binding ElementName=UsrCtrl, Path=Lunghezza}"
                   Fill="Coral"
                   Grid.RowSpan="2"

                   MouseLeftButtonDown="RettangoloProdotto_MouseLeftButtonDown"
                   MouseMove="RettangoloProdotto_MouseMove"/>

    </Grid>

</local:ProdottoCtrlBase>

1 个答案:

答案 0 :(得分:0)

只需将RotateTransform的centerX和centerY值设置为旋转元素的半宽和半高。这样,您可以将对象相对于其父级中的位置拖动,就像在未旋转时一样。

示例:

class SubView: UIImageView {

    var mySubView: UIImageView

    required init?(coder aDecoder: NSCoder) {

        mySubView = UIImageView()
        mySubView.backgroundColor = UIColor.cyan

        super.init(coder: aDecoder)
        self.addSubview(mySubView)

        mySubView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
        mySubView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
        mySubView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
        mySubView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
    }
}

在MouseMove-Handler中,您无需调整运动:

if(rotateTransform != null)
  { RotateTransform t = RotateTransform(rotateTransform.Angle + <rotationValue>, Width/2, Height/2);
    RenderTransform = t;
  }

希望这有帮助!

干杯,

亚历