前一段时间项目里面要实现一个鼠标拖动一个元素到另外一个元素上面并且赋值的功能,由于要在surface上运行,拖动的时候手指会挡住系统默认的拖动图标,导致用户意识不到自己是不是在拖动着东西,所以要解决这个问题。

初始想法

一开始在的设想是,拖动开始时新建一个元素要拖动的元素,然后设置次元素跟随鼠标移动,这里遇到个问题就是,当使用DoDragDrop事件的时候,捕捉不到鼠标的坐标变动,以至于无法让新建的元素跟随移动。要实现功能必须放弃DoDragDrop事件,但是当时很多已经写好的功能都是围绕这个事件的,不想再改,于是开始探索新的方式,虽然一开始浪费了一点时间,但是好处也不是没有,比如发现了GiveFeedback事件,于是就想到了第二种方案。

由于本来就是没有实现的方法,所以在此就不上代码了。

第二种方案

ButtonDown触发的时候,给元素添加MouseMove事件,当MouseMove触发的时候,获取到当前元素并生成图像转换为Cursor格式,在GiveFeedback中用以改变鼠标样式,添加GiveFeedback事件并启动DoDrapDrop。

        public void ViewElemenMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var viewElement = sender as ViewElement;
if (viewElemen == null) return;
viewElemen.MouseMove += ViewElemenOnPreviewMouseMove;
} private void PatientTitleOnPreviewMouseMove(object sender, MouseEventArgs mouseEventArgs)
{
var viewElement = sender as ViewElement;
if (viewElement == null) return;
HoloCursor = FormUtility.CreateCursor(viewElement);
viewElemen.RockStart();
viewElemen.GiveFeedback += DragSource_GiveFeedback;
DragDrop.DoDragDrop(viewElemen, Model, DragDropEffects.Copy);
viewElemen.MouseMove -= ViewElemenOnPreviewMouseMove;
viewElemen.GiveFeedback -= DragSource_GiveFeedback;
Mouse.SetCursor(Cursors.Arrow);
} void DragSource_GiveFeedback(object sender, GiveFeedbackEventArgs e)
{
var viewElement = sender as ViewElement;
if (viewElemen == null) return;
Mouse.SetCursor(HoloCursor);
e.UseDefaultCursors = false;
e.Handled = true;
}

之所以把这么麻烦是因为,鼠标点击事件还要有其他的业务操作,所以只能加在mousemove里面。
根据元素生成鼠标 FormUtility.CreateCursor:

        public static Cursor CreateCursor(UIElement element)
{
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(new Point(), element.DesiredSize)); var rtb =
new RenderTargetBitmap(
(int)element.DesiredSize.Width,
(int)element.DesiredSize.Height,
96, 96, PixelFormats.Pbgra32); rtb.Render(element); var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb)); using (var ms = new MemoryStream())
{
encoder.Save(ms);
using (var bmp = new System.Drawing.Bitmap(ms))
{
return InternalCreateCursor(bmp);
}
}
}
        private static Cursor InternalCreateCursor(System.Drawing.Bitmap bmp)
{
var iconInfo = new NativeMethods.IconInfo();
NativeMethods.GetIconInfo(bmp.GetHicon(), ref iconInfo); iconInfo.xHotspot = 125;
iconInfo.yHotspot = 65;
iconInfo.fIcon = false; SafeIconHandle cursorHandle = NativeMethods.CreateIconIndirect(ref iconInfo);
return CursorInteropHelper.Create(cursorHandle);
}
       [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
private class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeIconHandle()
: base(true)
{
} override protected bool ReleaseHandle()
{
return NativeMethods.DestroyIcon(handle);
}
}
        private static class NativeMethods
{
public struct IconInfo
{
public bool fIcon;
public int xHotspot;
public int yHotspot;
public IntPtr hbmMask;
public IntPtr hbmColor;
} [DllImport("user32.dll")]
public static extern SafeIconHandle CreateIconIndirect(ref IconInfo icon); [DllImport("user32.dll")]
public static extern bool DestroyIcon(IntPtr hIcon); [DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
}

RockStart是一个元素效果,即开始拖动的时候,该元素会左右摇晃,让用户更清楚的知道,自己拖动的是哪个元素。

        private Storyboard _sb = new Storyboard(){ FillBehavior = FillBehavior.Stop };

        public ViewElement()
{
InitializeComponent();
_sb.AutoReverse = true;
var dbAscending1 = new DoubleAnimation(0, 3, new Duration(TimeSpan.FromMilliseconds(100)));
_sb.Children.Add(dbAscending1);
Storyboard.SetTarget(dbAscending1, Border);
Storyboard.SetTargetProperty(dbAscending1, new PropertyPath("(Rectangle.RenderTransform).(RotateTransform.Angle)"));
var dbAscending2 = new DoubleAnimation(3, -3, new Duration(TimeSpan.FromMilliseconds(200)));
_sb.Children.Add(dbAscending2);
Storyboard.SetTarget(dbAscending2, Border);
Storyboard.SetTargetProperty(dbAscending2, new PropertyPath("(Rectangle.RenderTransform).(RotateTransform.Angle)"));
} public void RockStart()
{
Dispatcher.InvokeAsync(() => _sb.Begin(), DispatcherPriority.Background);
}

至此,功能完成。

WPF DragDrop事件元素跟随的更多相关文章

  1. WPF 在事件中绑定命令(不可以在模版中绑定命令)

    其实这也不属于MVVMLight系列中的东东了,没兴趣的朋友可以跳过这篇文章,本文主要介绍如何在WPF中实现将命令绑定到事件中. 上一篇中我们介绍了MVVMLight中的命令的用法,那么仅仅知道命令是 ...

  2. WPF自学入门(三)WPF路由事件之内置路由事件

    有没有想过在.NET中已经有了事件机制,为什么在WPF中不直接使用.NET事件要加入路由事件来取代事件呢?最直观的原因就是典型的WPF应用程序使用很多元素关联和组合起来,是否还记得在WPF自学入门(一 ...

  3. WPF路由事件二:路由事件的三种策略

    一.什么是路由事件 路由事件是一种可以针对元素树中的多个侦听器而不是仅仅针对引发该事件的对象调用处理程序的事件.路由事件是一个CLR事件. 路由事件与一般事件的区别在于:路由事件是一种用于元素树的事件 ...

  4. WPF 在事件中绑定命令

    导航:MVVMLight系列文章目录:<关于 MVVMLight 设计模式系列> 其实这也不属于MVVMLight系列中的东东了,没兴趣的朋友可以跳过这篇文章,本文主要介绍如何在WPF中实 ...

  5. js进阶 12-3 如何实现元素跟随鼠标移动

    js进阶 12-3 如何实现元素跟随鼠标移动 一.总结 一句话总结:获取鼠标位置,将鼠标位置设置为元素偏移即可. 1.用什么事件获取鼠标位置? 用mousemove可以获取鼠标移动的时候的位置 $(d ...

  6. WPF 路由事件 Event Routing

    原文:WPF 路由事件 Event Routing 1.路由事件介绍 之前介绍了WPF的新的依赖属性系统,本篇将介绍更高级的路由事件,替换了之前的.net普通事件.相比.net的事件,路由事件具有更强 ...

  7. Win7/Win8/Win8.1/Win10下的DragEnter DragDrop事件不触发

    Win7/Win8/Win8.1/Win10下的DragDrop事件不触发 2011-02-02  来自:博客园  字体大小:[大 中 小] 摘要:你的应用程序需要从windows资源管理器拖动文件到 ...

  8. Win7下的DragEnter、DragDrop事件不触发的解决方案

    Win7与原来的XP和Win2003相比,安全控制方面更严格.比如,当我们以administrator登陆XP或Win2003时,运行所有的程序即是以管理员的身份启动的.但当以administrato ...

  9. javascript元素跟随鼠标在指定区域运动

    元素跟随鼠标在指定区域运动通常是用在商城图片的放大镜中,下面是完整的Demo: <!DOCTYPE html> <html lang="en"> <h ...

随机推荐

  1. visual studio R6034解决方案集 从VC6.0 或VC2003 到VC2005发现的问题

    这是我转的一篇非常全的帖子 能查到的解决方法都在里面有提及: 我是使用 stdafx.h加入这句 code #pragma comment(linker, "\"/manifest ...

  2. 多设备同时安装apk问题(安卓)

    前几天在做安卓设备的多个设备同时安装的小脚本.因为目前我这边设备有点多,想顺便做一下安装的测试.而且因为本人负责公司所有的app测试人手上有点不足,就想通过这个办法去在安装的时候更方便省事一点. 本来 ...

  3. 带你快速了解CODESOFT 2015

    CODESOFT是知名的条码标签设计打印软件,现在又推出了最新版CODESOFT 2015,其新功能.大改进让人为之一振.下面跟随小编的脚步,走进CODESOFT 2015,看一看CODESOFT 2 ...

  4. jmeter随笔(9)--有两种编码风格,导致数据乱码

    问题:在一个网站,有两种编码风格,导致数据乱码 解决办法: 1.首先设置jmeter的配置文件 2.针对要求是utf-8格式的这样的请求,做单独的编码处理(beanshell处理) 3.运行,在htm ...

  5. CDN缓存策略FAQ

    1.CDN加速原理通过动态域名解析,网友的请求被分配到离自己最快的服务器.CDN服务器直接返回缓存文件或通过专线代理原站的内容.网络加速+内容缓存,有效提供访问速度 2.CDN节点数量全国多个机房,每 ...

  6. git从入门到精通

    1.git简介 由Linus在2005年花了两周时间完成,也就是开发Linux系统的大神研制. git特点: 自由和开放源码 隐形备份 安全 不需要强大的硬件 更简单的分支 对文件操作容易 2.文件操 ...

  7. 消费者端的Spring JMS 连接ActiveMQ接收生产者Oozie Server发送的Oozie作业执行结果

    一,介绍 Oozie是一个Hadoop工作流服务器,接收Client提交的作业(MapReduce作业)请求,并把该作业提交给MapReduce执行.同时,Oozie还可以实现消息通知功能,只要配置好 ...

  8. Eclipse 工作目录被破坏,导致Eclipse 打不开

    由于之前一直使用的的是 visual studio 的开发工具,对 java 的 Eclipse 工具比较陌生,在使用 eclipse 的过程中误删了工作目录的部分文件,导致在在下次启动 eclips ...

  9. epoll在socket通信中的应用

    当服务器需要服务多个客户时,需要使用并发通信,实现并发通信有以下几种方法: 1.在服务器中fork子进程来为每个客户服务  具体可参考http://www.cnblogs.com/ggjucheng/ ...

  10. SQL where 1=1的作用

    浅谈where 1=1 1.简单理解的话where 1=1 永真, where 1<>1 永假 2.1<>1 的用处:     用于只取结构不取数据的场合     例如:    ...