zoukankan      html  css  js  c++  java
  • 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、运行测试,随意拖动查看效果:

  • 相关阅读:
    [恢]hdu 2502
    [恢]hdu 1008
    [恢]hdu 2073
    [恢]hdu 2500
    [恢]hdu 2501
    [恢]hdu 2190
    [恢]hdu 2535
    [恢]hdu 2085
    [恢]hdu 2067
    [恢]hdu 2504
  • 原文地址:https://www.cnblogs.com/kuangxiangnice/p/5573869.html
Copyright © 2011-2022 走看看