1. 程式人生 > >WPF 矩形框8個控制點伸縮及拖拽

WPF 矩形框8個控制點伸縮及拖拽

控制 struct 超出 brush ldr endpoint ima idt osi

最近在研發圖片控件矩形框8個控制點進行控制邊框的大小、位置等信息,之前查閱了相關的信息,比如別人整合的類:ControlResizer 這個類雖然是好,但是很大程度上是有限制,換句話說,它需要你二次更改代碼和調整成適應你的代碼結構,否則很多邊框拖拉的時候無法使用,這也是當時使用的時候很頭疼的事情,廢話不多說,先上效果圖:

技術分享圖片技術分享圖片技術分享圖片

如上圖所示,分析下:有四個層,第一層是主窗體,第二層是傳入的圖片控件,第三層是遮罩、第四層也就是控制層(圖中顯示的可操作的藍色區域,以下稱為裁剪區),註意實現的效果是:

1、直接拖拽移動裁剪區,不能跑到圖片外面,並且在裁剪區之外的所有區域需要實時重新蒙上遮罩。

2、拖拉圖中的8個裁剪區藍色控制條,要實現控制條相關方向上的任意拖拉實現伸縮,並且有最小裁剪區域。

3、能根據傳入的圖片控件信息(圖中的包括寬-高-角度(30°),位置信息)進行定位和裁剪。

下面提供個人的方案進行參考,不一定是最佳方案,不過比對了很多人的控制點方案,我覺得這個可移植性比較高,適用於輕量級的操作,網上的都是各種類與類引用,然後一堆的與Windows自帶的東西結合比如Thumb類。相對復雜。不利於學習研究之用,總之我們只要掌握了原理,接下來解決問題就是比較容易。

解決方案步驟:

一:創建構造函數(模擬圖片控件信息,實際項目中可自行傳入信息僅供參考)。

示例:

     /// <summary>
        /// 構造一個圖片控件函數包含位置、角度等信息
        /// </summary>
        public class StructureSource
        {
            public Point Images_Point { get; set; }
            public double ImageAngle;
            public double ImageHeight;
            public double ImageWidth;
            
public BitmapImage ImageSource; public StructureSource() { Images_Point = new Point(200, 100); ImageAngle = 30.0; ImageSource = new BitmapImage(new Uri("C:\\Users\\Administrator\\Desktop\\CompanyLogo\\XXX.PNG")); ImageHeight = ImageSource.Height; ImageWidth = ImageSource.Width; } }

二:準備主窗體,主窗體需要準備好結構,前面提到了這種伸縮性的功能,它需要放在Canvas容器中進行操作,所以一定要註意它的結構性。

三:準備好一個用戶控件(在圖中是藍色控制條部分)。

四:初始化主窗體,包含根據圖片信息定位,角度等,遮罩,進行裁剪。

示例:

this.Loaded += (sender, ex) =>
             {
                 ImageItem = new StructureSource();
                 this._Images.Source = ImageItem.ImageSource;
                 this._Images.Height = ImageItem.ImageHeight;
                 this._Images.Width = ImageItem.ImageWidth;
                 //定位+旋轉角度
                 Matrix m = this._Images.RenderTransform.Value;
                 m.OffsetX = ImageItem.Images_Point.X;
                 m.OffsetY = ImageItem.Images_Point.Y;
                 m.RotateAt(ImageItem.ImageAngle, ImageItem.Images_Point.X, ImageItem.Images_Point.Y);
                 this._Images.RenderTransform = new MatrixTransform(m);
                 //設置背景為黑色
                 _GridBackGround.Background = Brushes.Black;
                 //添加內容
                 _ContentObject = new CuttingControl();
                 _Content.Children.Add(_ContentObject);
                 _ContentObject.SizeChanged += _ContentObject_SizeChanged;
                 _ContentObject.BackGroundDrag += _ContentObject_BackGroundDrag;
                 _Content.Height = ImageItem.ImageHeight;
                 _Content.Width = ImageItem.ImageWidth;
                 //定位+翻轉角度
                 Matrix m2 = this._Content.RenderTransform.Value;
                 m2.OffsetX = ImageItem.Images_Point.X;
                 m2.OffsetY = ImageItem.Images_Point.Y;
                 m2.RotateAt(ImageItem.ImageAngle, m2.OffsetX, m2.OffsetY);
                 this._Content.RenderTransform = new MatrixTransform(m2);

                 //對選定的區域進行裁剪

                 CroppedRegionMethod(this._Content.RenderTransform);
             };

五:核心功能代碼。拖拽部分(采用矩陣拖拽)

 /// <summary>
        /// 移動具體方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TryToMoveForward(object sender, MouseEventArgs e)
        {
            CroppedRegionEndPoint = e.GetPosition((UIElement)this.Parent);
            var MatrixCroppedRegion = this.RenderTransform.Value;

            var offsetX = CroppedRegionEndPoint.X - CroppedRegionStartPoint.X;
            var OffsetY = CroppedRegionEndPoint.Y - CroppedRegionStartPoint.Y;
            if (offsetX <= 0)
            {
                offsetX = 0;
            }
            else
            {
                if (offsetX + this.ActualWidth >= ((UIElement)this.Parent as FrameworkElement).Width)
                {
                    offsetX = ((UIElement)this.Parent as FrameworkElement).Width - this.ActualWidth;
                }
            }
            if (OffsetY <= 0)
            {
                OffsetY = 0;
            }
            else
            {
                if (OffsetY + this.ActualHeight >= ((UIElement)this.Parent as FrameworkElement).Height)
                {
                    OffsetY = ((UIElement)this.Parent as FrameworkElement).Height - this.ActualHeight;
                }
            }

            MatrixCroppedRegion.OffsetX = offsetX;
            MatrixCroppedRegion.OffsetY = OffsetY;

            this.RenderTransform = new MatrixTransform(MatrixCroppedRegion);

            ClippedRegionChanged(this.RenderTransform, e);
        }

六:核心代碼(控制條拖拉、伸縮)

示例:

/// <summary>
        /// 嘗試拖拽邊框
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TryToMoveBoarder(object sender, MouseEventArgs e)
        {
            CroppedBoarderEndPoint = e.GetPosition((UIElement)this.Parent);

            //控制裁剪區域大小
            var OffsetX = CroppedBoarderEndPoint.X - CroppedBoarderStartPoint.X;
            var OffsetY = CroppedBoarderEndPoint.Y - CroppedBoarderStartPoint.Y;

            //控制裁剪區域位置
            var MoveX = CroppedBoarderEndPoint.X - CroppedBoarderPanningStartPoint.X;
            var MoveY = CroppedBoarderEndPoint.Y - CroppedBoarderPanningStartPoint.Y;

            //放大拖拉邊框
            switch (sender)
            {
                case "_LeftTop"://OK(研發) OK(修正) OK(測試)
                    #region --左上角控制點--
                    if (CroppedRegionWidth - OffsetX >= this.MinWidth)
                    {
                        //防止寬度先到達臨界點而高度不能變化
                        this.Width = CroppedRegionWidth - OffsetX;
                        TryToMoveChangingBoarder("_LeftTop", MoveX, MoveY, "X");
                        //修正超出部分
                        if (this.RenderTransform.Value.OffsetX <= 0)
                        {
                            this.Width = this.Width + MoveX;
                        }
                    }

                    if (CroppedRegionHeight - OffsetY >= this.MinHeight)
                    {
                        this.Height = CroppedRegionHeight - OffsetY;
                        TryToMoveChangingBoarder("_LeftTop", MoveX, MoveY, "Y");
                        //修正超出部分
                        if (this.RenderTransform.Value.OffsetY <= 0)
                        {
                            this.Height = this.Height + MoveY;
                        }
                    }

                    #endregion
                    break;
                case "_CenterTop"://OK(研發) OK(修正) OK(測試)
                    #region --頂中部控制點--
                    if (CroppedRegionHeight - OffsetY < this.MinHeight)
                        return;

                    this.Height = CroppedRegionHeight - OffsetY;
                    TryToMoveChangingBoarder("_CenterTop", MoveX, MoveY, "");
                    //修正超出部分
                    if (this.RenderTransform.Value.OffsetY <= 0)
                    {
                        this.Height = this.Height + MoveY;
                    }

                    #endregion
                    break;
                case "_RightTop"://OK(研發) OK(修正) OK(測試)
                    #region --右上角控制點--
                    if (CroppedRegionWidth + OffsetX < this.MinWidth)
                    {
                        //防止寬度先到達臨界點而高度不能變化
                        if (MoveY >= 0)
                        {
                            if (CroppedRegionHeight - OffsetY < this.MinHeight)
                                return;
                            this.Height = CroppedRegionHeight - OffsetY;
                            TryToMoveChangingBoarder("_RightTop", MoveX, MoveY, "");
                        }
                    }
                    else
                    {
                        this.Width = CroppedRegionWidth + OffsetX;
                        if (CroppedRegionHeight - OffsetY >= this.MinHeight)
                        {
                            this.Height = CroppedRegionHeight - OffsetY;
                            TryToMoveChangingBoarder("_RightTop", MoveX, MoveY, "");
                            //修正超出部分
                            if (this.RenderTransform.Value.OffsetY <= 0)
                            {
                                this.Height = this.Height + MoveY;
                            }
                        }

                    }
                    #endregion
                    break;
                case "_LeftCenter"://OK(研發) OK(修正) OK(測試)
                    #region --左中部控制點--
                    if (CroppedRegionWidth - OffsetX < this.MinWidth)
                        return;

                    this.Width = CroppedRegionWidth - OffsetX;
                    TryToMoveChangingBoarder("_LeftCenter", MoveX, MoveY, "");
                    //修正超出部分
                    if (this.RenderTransform.Value.OffsetX <= 0)
                    {
                        this.Width = this.Width + MoveX;
                    }
                    #endregion
                    break;
                case "_RightCenter"://OK(研發) OK(修正) OK(測試)
                    #region --右中部控制點--
                    if (CroppedRegionWidth + OffsetX < this.MinWidth)
                        return;
                    this.Width = CroppedRegionWidth + OffsetX;
                    #endregion
                    break;
                case "_LeftBottom": //OK(研發) OK(修正) OK(測試)
                    #region --左下角控制點--
                    if (CroppedRegionWidth - OffsetX >= this.MinWidth)
                    {
                        //防止寬度先到達臨界點而高度不能變化
                        this.Width = CroppedRegionWidth - OffsetX;
                        TryToMoveChangingBoarder("_LeftBottom", MoveX, MoveY, "X");
                        //修正超出部分
                        if (this.RenderTransform.Value.OffsetX <= 0)
                        {
                            this.Width = this.Width + MoveX;
                        }
                    }


                    if (CroppedRegionHeight + OffsetY >= this.MinHeight)
                    {
                        this.Height = CroppedRegionHeight + OffsetY;
                    }
                    #endregion
                    break;
                case "_CenterBottom"://OK(研發) OK(修正) OK(測試)
                    #region --底中部控制點--
                    if (CroppedRegionHeight + OffsetY < this.MinHeight)
                        return;
                    this.Height = CroppedRegionHeight + OffsetY;
                    #endregion
                    break;
                case "_RightBottom"://OK(研發) OK(修正) OK(測試)
                    #region --右下角控制點--
                    if (CroppedRegionWidth + OffsetX < this.MinWidth)
                    {
                        //防止寬度先到達臨界點而高度不能變化
                        if (CroppedRegionHeight + OffsetY < this.MinHeight)
                            return;
                        this.Height = CroppedRegionHeight + OffsetY;
                    }
                    else
                    {
                        this.Width = CroppedRegionWidth + OffsetX;
                        if (CroppedRegionHeight + OffsetY >= this.MinHeight)
                        {
                            this.Height = CroppedRegionHeight + OffsetY;
                        }
                    }
                    #endregion
                    break;
            }
            #region --限定邊界範圍針對無動畫,修正長寬--

            if (this.RenderTransform.Value.OffsetX + this.Width >= ((UIElement)this.Parent as FrameworkElement).Width)
                this.Width = ((UIElement)this.Parent as FrameworkElement).Width - this.RenderTransform.Value.OffsetX;

            if (this.RenderTransform.Value.OffsetY + this.Height >= ((UIElement)this.Parent as FrameworkElement).Height)
                this.Height = ((UIElement)this.Parent as FrameworkElement).Height - this.RenderTransform.Value.OffsetY;







            #endregion

            if (this.Height >= this.MinHeight)
                ClippedRegionChanged(this.RenderTransform, e);
        }





        /// <summary>
        /// 矩陣平移
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="MoveX">平移的X軸距離</param>
        /// <param name="MoveY">平移的Y軸距離</param>
        private void TryToMoveChangingBoarder(string sender, double MoveX, double MoveY, string DirectionXY)
        {
            var m = this.RenderTransform.Value;
            switch (sender)
            {
                case "_LeftTop":
                    if (DirectionXY == "X")
                        m.OffsetX = MoveX;
                    else
                    {
                        if (MoveY <= 0)
                            m.OffsetY = 0;
                        else
                            m.OffsetY = MoveY;
                    }
                    break;
                case "_CenterTop":
                    if (MoveY <= 0)
                        m.OffsetY = 0;
                    else
                        m.OffsetY = MoveY;
                    break;
                case "_RightTop":
                    if (MoveY <= 0)
                        m.OffsetY = 0;
                    else
                        m.OffsetY = MoveY;
                    break;
                case "_LeftCenter":
                    m.OffsetX = MoveX;
                    break;
                case "_LeftBottom":
                    if (DirectionXY == "X")
                        m.OffsetX = MoveX;
                    else
                        m.OffsetY = MoveY;
                    break;
            }
            //限制邊框不出裁剪區域
            if (m.OffsetX < 0)
                m.OffsetX = 0;

            this.RenderTransform = new MatrixTransform(m);
        }

目前已經整合成用戶控件,方便之後的項目進行引用。這邊提供了核心的拖拽,伸縮代碼,作為筆記方便以後進行查閱。

WPF 矩形框8個控制點伸縮及拖拽