WPF中的拖放(三)

2010年2月21日 分类: WPF

上一篇,我们实现了同一窗体间的拖放,并且显示鼠标跟随效果,今天,我们来实现不同窗体之间的拖放,因为不是用一个窗体,而Adorner(装饰器)只能在父窗体内移动,所以,我们实现不同窗体之间显示鼠标跟随效果,就要再新建一个窗体来显示鼠标跟随的内容。我们先看一下完成后的效果图。

由于要获得鼠标相对屏幕坐标和把拖放窗体的位置带到放置窗体的位置,需要使用Win32 API来完成,我们先创建一个类,代码如下:

public static class Win32
{
    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public POINT(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    }

    public static Int32 GWL_EXSTYLE = -20;
    public static Int32 WS_EX_LAYERED = 0x00080000;
    public static Int32 WS_EX_TRANSPARENT = 0x00000020;

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern bool GetCursorPos(out POINT pt);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern Int32 GetWindowLong(IntPtr hWnd, Int32 nIndex);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern Int32 SetWindowLong(IntPtr hWnd, Int32 nIndex, Int32 newVal);
}

我们通过GetCursorPos()方法获得鼠标坐标,GetWindowLong()、SetWindowLong()方法获得和设置窗体属性。

接下来,我们编写拖拽窗体Window1.xaml.cs,代码如下

public partial class Window1 : Window
{
    //显示拖拽内容的窗体
    private Window _dragdropWindow = null;
    //实例化Window2用于放置操作
    Window2 win = new Window2();

    public Window1()
    {
        InitializeComponent();

        win.Show();

        this.rectangle1.PreviewMouseMove += new MouseEventHandler(rectangle1_PreviewMouseMove);
    }

    void rectangle1_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            this.StartDragWindow(e);
        }
    }

    private void StartDragWindow(MouseEventArgs e)
    {
        QueryContinueDragEventHandler queryhandler = new QueryContinueDragEventHandler(DragSource_QueryContinueDrag);
        this.rectangle1.QueryContinueDrag += queryhandler;

        this.CreateDragDropWindow(this.rectangle1);
        DataObject data = new DataObject(typeof(string), "Moved!!!");
        this._dragdropWindow.Show();
        DragDropEffects de = DragDrop.DoDragDrop(this.rectangle1, data, DragDropEffects.Move);
        this.DestroyDragDropWindow();

        this.rectangle1.QueryContinueDrag -= queryhandler;
    }

    void DragSource_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
    {
        this.UpdateWindowLocation();
    }

    /// <summary>
    /// 更新拖拽窗体位置
    /// </summary>
    private void UpdateWindowLocation()
    {
        if (this._dragdropWindow != null)
        {
            Win32.POINT p;
            if (!Win32.GetCursorPos(out p))
            {
                return;
            }
            this._dragdropWindow.Left = (double)p.X;
            this._dragdropWindow.Top = (double)p.Y;
        }
    }

    /// <summary>
    /// 创建拖拽窗体
    /// </summary>
    /// <param name="dragElement"></param>
    private void CreateDragDropWindow(Visual dragElement)
    {
        this._dragdropWindow = new Window();
        this._dragdropWindow.WindowStyle = WindowStyle.None;
        this._dragdropWindow.Opacity = 0.6;
        this._dragdropWindow.AllowsTransparency = true;
        this._dragdropWindow.AllowDrop = false;
        this._dragdropWindow.Background = null;
        this._dragdropWindow.IsHitTestVisible = false;
        this._dragdropWindow.SizeToContent = SizeToContent.WidthAndHeight;
        this._dragdropWindow.Topmost = true;
        this._dragdropWindow.ShowInTaskbar = false;

        this._dragdropWindow.SourceInitialized += new EventHandler(
        delegate(object sender, EventArgs args)
        {
            PresentationSource windowSource = PresentationSource.FromVisual(this._dragdropWindow);
            IntPtr handle = ((System.Windows.Interop.HwndSource)windowSource).Handle;

            Int32 styles = Win32.GetWindowLong(handle, Win32.GWL_EXSTYLE);
            Win32.SetWindowLong(handle, Win32.GWL_EXSTYLE, styles | Win32.WS_EX_LAYERED | Win32.WS_EX_TRANSPARENT);
        });

        Rectangle r = new Rectangle();
        r.Width = ((FrameworkElement)dragElement).ActualWidth;
        r.Height = ((FrameworkElement)dragElement).ActualHeight;
        r.Fill = new VisualBrush(dragElement);
        this._dragdropWindow.Content = r;

        this.UpdateWindowLocation();
    }

    /// <summary>
    /// 销毁托抓窗体
    /// </summary>
    private void DestroyDragDropWindow()
    {
        if (this._dragdropWindow != null)
        {
            this._dragdropWindow.Close();
            this._dragdropWindow = null;
        }
    }
}

关键代码在StartDragWindow(MouseEventArgs)这个方法,开始拖拽时,我们先创建_dragdropWindow这个拖拽窗体,并进行相应初始化操作,定义被拖拽物体(这里为矩形)状态发生变化时调用UpdateWindowLocation()方法,更新拖拽窗体位置,拖拽完成后调用DestroyDragDropWindow()方法,销毁拖拽窗体,这一系列过程,达到完成窗体拖拽操作。

最后,我们编写放置窗体Window2.xaml.cs,代码如下

public partial class Window2 : Window
{
    public Window2()
    {
        InitializeComponent();

        this.AllowDrop = true;

        this.DragOver += new DragEventHandler(canvas2_DragOver);
        this.Drop += new DragEventHandler(canvas2_Drop);
    }

    void canvas2_Drop(object sender, DragEventArgs e)
    {
        IDataObject data = e.Data;

        if (data.GetDataPresent(typeof(string)))
        {
            string msg = data.GetData(typeof(string)) as string;
            MessageBox.Show(msg);
        }
    }

    void canvas2_DragOver(object sender, DragEventArgs e)
    {
        if (!e.Data.GetDataPresent(typeof(string)))
        {
            e.Effects = DragDropEffects.None;
            e.Handled = true;
        }
    }
}

这里的代码很简单,WPF的拖放(一)已经有说明,有什么不明白就看文章一吧。
本文代码下载

原创文章,转载请注明: 转载自.NET开发者

本文链接地址: WPF中的拖放(三)

文章的脚注信息由WordPress的wp-posturl插件自动生成

Related posts:

  1. Winform/WPF实例中的相互操作
  2. WPF中单击标题行可排序的GridView
  3. WPF中的拖放(二)
  4. WPF中的拖放(一)
  5. WPF最大化避免覆盖任务栏
标签: ,

1条评论 于 “WPF中的拖放(三)”

  1. 2010年2月23日14:22
    1

    代码是很简单。

Leave a Comment