WPF 使用鼠标拖动一个控件的实现[2018.7.15]
原文:WPF 使用鼠标拖动一个控件的实现[2018.7.15]
Q:已经把一个Shape和一个TextBlock组合起来放到了一个Grid中,现在想要实现用鼠标拖动这个Grid到任意位置的功能,如何做?
<Grid Height="50" Width="50">
<Ellipse Fill="Yellow" Stroke="Blue" Height="50" Width="50" HorizontalAlignment="Left"></Ellipse>
<TextBlock Text="5" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
</Grid>
A:在stackoverflow上找到解决方法。首先,为这个Grid添加三个鼠标事件
<Grid Height="50" Width="50" MouseLeftButtonDown="grid_MouseLeftButtonDown" MouseLeftButtonUp="
grid_MouseLeftButtonUp" MouseMove="grid_MouseMove">
<Ellipse Fill="Yellow" Stroke="Blue" Height="50" Width="50" HorizontalAlignment="Left"></Ellipse>
<TextBlock Text="5" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
</Grid>
在cs文件中为这三个事件添加实现:
private bool isDragging;
private Point clickPosition;
private void grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
isDragging = true;
var draggableElement = sender as UIElement;
clickPosition = e.GetPosition(this);
draggableElement.CaptureMouse();
}
private void grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
isDragging = false;
var draggableElement = sender as UIElement;
draggableElement.ReleaseMouseCapture();
}
private void grid_MouseMove(object sender, MouseEventArgs e)
{
var draggableElement = sender as UIElement;
if (isDragging && draggableElement != null)
{
Point currentPosition = e.GetPosition(this.Parent as UIElement);
var transform = draggableElement.RenderTransform as TranslateTransform;
if (transform == null)
{
transform = new TranslateTransform();
draggableElement.RenderTransform = transform;
}
transform.X = currentPosition.X - clickPosition.X;
transform.Y = currentPosition.Y - clickPosition.Y;
}
}
每个控件有一个RenderTransform属性,它接收一个对象。TranslateTransform是RenderTransform的一个子类,它的实例可以赋给控件的RenderTransform属性,表示以当前控件为原点进行的平移操作。
【---2018.7.17添加---】
上面这段c#代码有问题。当拖动控件移动后,松开鼠标,如果再次想要拖动该控件,在鼠标刚按下时控件会回到原点。
出现这个问题是因为在MouseLeftButtonDown事件发生后,立即发生MouseMove事件,currentPosition和clickPosition相等,导致transform的X和Y属性都为0。从而grid的RenderTransform属性指示将控件重新绘制在grid的起始位置。
对于RenderTransform属性来说,原点是多少?应该是grid控件对象被创建时的坐标。RenderTransform指示的移动都是以这个坐标轴为参考的。
解决这个问题的方法是,在grid_MouseMove()中,每次移动的时候,要加上上一次拖拽结束时控件的相对坐标。
首先为这个grid添加一个名字,并使用RenderTransform属性
<Grid Height="50" Width="50" Name="myGrid" MouseLeftButtonDown="grid_MouseLeftButtonDown" MouseLeftButtonUp="
grid_MouseLeftButtonUp" MouseMove="grid_MouseMove">
<Ellipse Fill="Yellow" Stroke="Blue" Height="50" Width="50" HorizontalAlignment="Left"></Ellipse>
<TextBlock Text="5" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
<Grid.RenderTransform>
<TranslateTransform x:Name="tt" />
</RenderTransform>
</Grid>
然后,将cs代码中的clickPosition取消,换一个名字,比如叫startPosition,用来记录该控件在任一时刻离自己的原点的相对坐标。在grid_MouseLeftButtonDown方法中,不记录鼠标点击的位置坐标,而是记录鼠标被按下时这个位置离控件原点的距离,即刚刚定义的startPosition。
在grid_MouseMove方法中,由于grid的RenderTransform早有定义,所以不用进行是否null的判断。之后transform变量的值,应该为当前坐标currentPosition与参考点startPosition之差。
private bool isDragging;
private Point startPosition;
private void grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
isDragging = true;
var draggableElement = sender as UIElement;
var clickPosition = e.GetPosition(this);
var transform = draggableElement.RenderTranform as TranslateTransform;
startPosition.X = clickPosition.X - transform.X; //注意减号
startPosition.Y = clickPosition.Y - transform.Y;
draggableElement.CaptureMouse();
}
private void grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
isDragging = false;
var draggableElement = sender as UIElement;
draggableElement.ReleaseMouseCapture();
}
private void grid_MouseMove(object sender, MouseEventArgs e)
{
var draggableElement = sender as UIElement;
if (isDragging && draggableElement != null)
{
Point currentPosition = e.GetPosition(this.Parent as UIElement);
var transform = draggableElement.RenderTransform as TranslateTransform;
transform.X = currentPosition.X - startPosition.X;
transform.Y = currentPosition.Y - startPosition.Y;
}
}
WPF 使用鼠标拖动一个控件的实现[2018.7.15]的更多相关文章
- [转]C#鼠标拖动任意控件
C#鼠标拖动任意控件(winform) 分类: c#2011-08-15 22:51 178人阅读 评论(0) 收藏 举报 winformc#userwindowsobjectapi using Sy ...
- C# 运行时通过鼠标拖动改变控件的大小
来源:http://blog.csdn.net/yanleigis/article/details/1819447 using System; using System.Collections.Gen ...
- C#设置一个控件可以鼠标拖动
C#设置一个控件可以鼠标拖动: 新建一个C#项目, 创建一个label控件, 设置label的鼠标按下和抬起事件分别为:label1_MouseDown和label1_MouseUp. 对代码进行如下 ...
- wpf鼠标捕获与控件交互——UIElement.CaptureMouse
应用场景是这样的,我需要拖动一个元素在屏幕上移动,注册了被移动元素的MouseMove事件,但是当鼠标移到被移动元素的外面时,移动失效,且鼠标的手势变成了普通的箭头形状,于是就找到了以下的解决方案. ...
- c# 鼠标点击控件即拖动窗体
在编程中,有时打开的窗体没有边框,但是我们仍然想在鼠标放在窗体上就能拖动窗体,这样我们只需要以窗体中的一个控件为参考,我们在这里以panel为例子: public class PanelNew : P ...
- wpf研究之道-datagrid控件(1)
"想要说些什么 又不知从何说起",每当想要写一些关于wpf的文章,总是沉思良久,怕自己写不好.今天我想要说的是wpf中datagrid控件.我们先来看看它在整个类的层次结构: ...
- WPF 动画:同为控件不同命 - 简书
原文:WPF 动画:同为控件不同命 - 简书 1. 及格与优秀 读大学的时候,有一门课的作业是用 PPT 展示. 但是我们很多同学都把 PPT 当做 Word 来用,就单纯地往里面堆文字. 大家都单纯 ...
- c# Winform 继承窗体 无法拖动修改控件大小
问题描述: 一个窗体集成父窗体,发现无法直接拖动修改的控件,比如修改大小等 特征: 不禁使父窗体控件,就算新加一个控件也会这样:鼠标放到控件移动手方块上会出现一个“继承的控件”的tooptip, 异常 ...
- WPF常用方法,事件驱动和控件遍历
//初始化数据,默认选中第一项,事件驱动 RadioButton btn = FuncClass.GetChildObject<RadioButton>(this.stackPanel1, ...
随机推荐
- Oracle 12C R2 on Linux 7.X Data Guard 搭建文档
1.查看主机和数据库信息 [oracle@oracle1 ~]$ sqlplus / as sysdba SQL*Plus: Release 12.2.0.1.0 Production on ...
- python 的 reshape强制转换格式的用途
shu=[[ 0.03046758], [ 0.05485586], [ 0.03282908], [ 0.02107211], [ 0.0391144 ], [ 0.07847244], [ 0.1 ...
- 原生js大总结六
051.如何打印当前浏览器的版本等信息 navigator.userAgent 返回包含浏览器版本等信息的字符串 ,常用于判断浏览器版本及使用设备(PC或者移动端 052 .在浏览器地址栏 ...
- 【Educational Codeforces Round 33 C】 Rumor
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 显然最后会形成多个集合,每个集合里面的人能够可以互相到达. 则维护并查集的时候,顺便维护一下每个集合里面的最小值就好. 最后答案就为 ...
- 洛谷 P2118 比例简化
P2118 比例简化 题目描述 在社交媒体上,经常会看到针对某一个观点同意与否的民意调查以及结果.例如,对某一观点表示支持的有1498 人,反对的有 902人,那么赞同与反对的比例可以简单的记为149 ...
- Python写爬虫-爬甘农大学校新闻
Python写网络爬虫(一) 关于Python: 学过C. 学过C++. 最后还是学Java来吃饭. 一直在Java的小世界里混迹. 有句话说: "Life is short, you ne ...
- QWaitCondition 的正确使用方法(通过 mutex 把有严格时序要求的代码保护起来,同时把 wakeAll() 也用同一个 mutex 保护起来)
简单用法 QWaitCondition 用于多线程的同步,一个线程调用QWaitCondition::wait() 阻塞等待,直到另一个线程调用QWaitCondition::wake() 唤醒才继续 ...
- C# 获取文件路径,读取项目中某程序集下文件
获取文件路径 ------------------------------------------------------------------------- winform获取文件路径: stri ...
- HDU 2147kiki's game
KIKI和zz一起玩跳棋游戏,KIKI先.跳棋棋盘有n行m列.在顶行的最右侧位置放上一枚硬币.每次每个人可以把硬币移动到左边,下边或是左下边的空格中.最后不能移动硬币的那个人将输掉比赛. P点:即必败 ...
- PHP SPL标准库之数据结构栈(SplStack)介绍(基础array已经可以解决很多问题了,现在开始解决问题)
PHP SPL标准库之数据结构栈(SplStack)介绍(基础array已经可以解决很多问题了,现在开始解决问题) 一.总结 SplStack就是继承双链表(SplDoublyLinkedList)实 ...