WPF學習- AllowDrop 用戶控件啟用拖放功能


知識點:

  • 創建自定義用戶控件(UserControl)
  • 使用戶控件成為拖動源
  • 使用戶控件成為放置目標
  • 使面板能夠接收從用戶控件放置的數據

創建項目:

1、新建WPF項目(Wpf-AllowDrop)

2、在MainWindow.xaml的 Grid控件添加源碼

       <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <StackPanel Grid.Column="0"
            Background="Beige">
            <TextBox Width="Auto" Margin="2"
             Text="green"/>
        </StackPanel>
        <StackPanel Grid.Column="1"
            Background="Bisque">
        </StackPanel>

設計顯示效果如下:

項目中添加用戶控件

1、“項目”--> “添加用戶控件”

2、重命名為Circle.xaml,添加。

3、在Circle.xaml的Grid中添加 Ellipse標簽

    <Ellipse x:Name="circleUI" 
         Height="100" Width="100"
         Fill="Blue" />

顯示效果如下:

4、在Circle.xaml.cs源文件中,重寫構造函數

public partial class Circle : UserControl
    {
        public Circle()
        {
            InitializeComponent();
        }

        public Circle(Circle c)  //重寫構造
        {
            InitializeComponent();
            this.circleUI.Height = c.circleUI.Height;
            this.circleUI.Width = c.circleUI.Height;
            this.circleUI.Fill = c.circleUI.Fill;
        }
    }

5、在MainWindow.xaml中的第一個StackPanel中添加兩個自定義的圓控件

     <StackPanel Grid.Column="0"
            Background="Beige">
            <TextBox Width="Auto" Margin="2" Text="green"/>
            <!--添加圓控件-->
            <local:Circle Margin="2" /> 
            <local:Circle Margin="2" />
        </StackPanel>

效果圖如下:

用戶控件實現拖動源事件

1、在Circle.xaml.cs中重寫OnMouseMove事件

    protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            // 判斷左鍵是否按下
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                //聲明DataObject,並打包圓控件的圖像繪制方式(包含顏色)、高度及其副本。
                DataObject data = new DataObject();
                data.SetData(DataFormats.StringFormat, circleUI.Fill.ToString());
                data.SetData("Double", circleUI.Height);
                data.SetData("Object", this);

                //使用DragDrop的DoDragDrop方法開啟拖動功能。拖動方式為拖動復制或移動
                DragDrop.DoDragDrop(this, data, DragDropEffects.Copy | DragDropEffects.Move);
            }
        }

2、運行測試:單擊一個圓,任意拖動查看效果:

3、重寫OnGiveFeedback,增強拖動時,光標反饋效果。

     protected override void OnGiveFeedback(GiveFeedbackEventArgs e)
        {
            base.OnGiveFeedback(e);
            
            //Effects獲取拖動類型
            if (e.Effects.HasFlag(DragDropEffects.Copy))
            {
                Mouse.SetCursor(Cursors.Cross); //拖動復制顯示紅十字
            }
            else if (e.Effects.HasFlag(DragDropEffects.Move))
            {
                Mouse.SetCursor(Cursors.Pen); //移動顯示筆形
            }
            else
            {
                Mouse.SetCursor(Cursors.No);
            }
            e.Handled = true;
        }

4、運行測試:單擊一個圓,任意拖動查看效果(主要指針效果)。

用戶控件成為放置目標

1、在Circle.xaml的UserControl標記中添加AllowDrop屬性為"True"

    <UserControl x:Class="Wpf_AllowDrop.Circle"
             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:Wpf_AllowDrop"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" AllowDrop="True">

2、在Circle.xaml.cs源碼文件中,重寫OnDrop事件方法

     protected override void OnDrop(DragEventArgs e)
        {
            base.OnDrop(e);

            //檢查數據是否包含制定字符串類型數據
            if (e.Data.GetDataPresent(DataFormats.StringFormat))
            {
                //獲取字符串
                string dataString = (string)e.Data.GetData(DataFormats.StringFormat);

                //使用BrushConverter將字符串轉換成Brush對象並應用於提供圓形控件 UI 的 Ellipse 的 Fill
                BrushConverter converter = new BrushConverter();
                if (converter.IsValid(dataString))
                {
                    Brush newFill = (Brush)converter.ConvertFromString(dataString);
                    circleUI.Fill = newFill;

                    if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
                    {
                        e.Effects = DragDropEffects.Copy;
                    }
                    else
                    {
                        e.Effects = DragDropEffects.Move;
                    }
                }
            }
            e.Handled = true;
        }

3、運行測試,查看TextBox文本green拖入圓形區域后效果:

4、重寫OnDragOver,禁止無效顏色拖入圓形控件(鼠標顯示禁止)

     protected override void OnDragOver(DragEventArgs e)
        {
            base.OnDragOver(e);

            //設置Effects 為不接受數據
            e.Effects = DragDropEffects.None;

            if (e.Data.GetDataPresent(DataFormats.StringFormat))
            {
                string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
                BrushConverter converter = new BrushConverter();

                //判斷拖動值是否有效
                if (converter.IsValid(dataString))
                {
                    //判斷Ctrl鍵是否按下
                    if (e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))
                    {
                        e.Effects = DragDropEffects.Copy;
                    }
                    else
                    {
                        e.Effects = DragDropEffects.Move;
                    }
                }
            }
            e.Handled = true;
        }

5、運行測試,拖動Gre到圓型中,查看鼠標變化

6、添加一個Brush變量用來暫時存放目標控件屬性,重寫OnDrageEnter和OneDrageLeave,增加預覽效果,未放置則離開,目標控件顏色不發生變化。

 public partial class Circle : UserControl
    {
        private Brush _previousFill = null; //聲明私有Brush,初始值為null
    protected override void OnDragEnter(DragEventArgs e)
        {
            base.OnDragEnter(e);
           //控件原始屬性存放在全局私有Brush對象中
            _previousFill = circleUI.Fill;

            if (e.Data.GetDataPresent(DataFormats.StringFormat))
            {
                string dataString = (string)e.Data.GetData(DataFormats.StringFormat);
                BrushConverter converter = new BrushConverter();
                if (converter.IsValid(dataString))
                {
                    Brush newFill = (Brush)converter.ConvertFromString(dataString.ToString());
                    circleUI.Fill = newFill;
                }
            }
        }
     protected override void OnDragLeave(DragEventArgs e)
        {
            base.OnDragLeave(e);
           //若直接離開(未釋放鼠標),把存在全局私有變量_previousFill屬性重新賦值
            circleUI.Fill = _previousFill;
        }

7、運行測試,拖動時先不釋放鼠標測試,再是否鼠標測試,查看效果:

使面板能夠接受放置的數據

1、在MainWindow.xaml 的兩個StackPanel控件中添加DragOver事件處理,名稱為panel_DragOver,以及添加Drop事件處理,名稱為panel_drop。並設置AllowDrop屬性為"True"。

    <StackPanel Grid.Column="0"
            Background="Beige" 
            AllowDrop="True"        
            DragOver="panel_DragOver"
            Drop="panel_Drop">
            <TextBox Width="Auto" Margin="2" Text="green"/>
            <!--添加圓控件-->
            <local:Circle Margin="2" /> 
            <local:Circle Margin="2" />
        </StackPanel>
        <StackPanel Grid.Column="1"
            Background="Bisque"
            AllowDrop="True"
            DragOver="panel_DragOver"
            Drop="panel_Drop">
        </StackPanel>

2、在MainWindow.xaml.cs中實現兩個事件處理方法:

     private void panel_DragOver(object sender, DragEventArgs e)
        {
            //檢查拖動的數據是否包含由圓形用戶控件打包在 DataObject 中並且在 DoDragDrop 調用中傳遞的“對象”數據
            if (e.Data.GetDataPresent("Object"))
            {
                if (e.KeyStates == DragDropKeyStates.ControlKey)
                {
                    e.Effects = DragDropEffects.Copy;
                }
                else
                {
                    e.Effects = DragDropEffects.Move;
                }
            }
        }
    private void panel_Drop(object sender, DragEventArgs e)
        {
            if (e.Handled == false)
            {
                Panel _panel = (Panel)sender; //取得當前panel對象
                UIElement _element = (UIElement)e.Data.GetData("Object");//移動對象轉換成WPF核心基類對象 

                if (_panel != null && _element != null)
                {
                    //獲取移動對象的父對象
                    Panel _parent = (Panel)VisualTreeHelper.GetParent(_element);

                    if (_parent != null)
                    {
                        if (e.KeyStates == DragDropKeyStates.ControlKey &&
                            e.AllowedEffects.HasFlag(DragDropEffects.Copy))
                        {
                            Circle _circle = new Circle((Circle)_element);
                            _panel.Children.Add(_circle); //在其子元素中添加對象
                           
                            e.Effects = DragDropEffects.Copy;
                        }
                        else if (e.AllowedEffects.HasFlag(DragDropEffects.Move))
                        {
                            _parent.Children.Remove(_element); //移動時,從父對象中移除源文件
                            _panel.Children.Add(_element);

                            e.Effects = DragDropEffects.Move;
                        }
                    }
                }
            }
        }

3、運行測試,隨意拖動查看效果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM