【WinRT】让控件飞,WinRT 中实现 web 中的 dragable 效果
由于在 xaml 体系中,控件没有传统 WebForm 中的 Left、Top、Right、Bottom 这些属性,取而代之的是按比例(像 Grid)等等的响应布局。但是,传统的这些设置 Left、Top 的硬编码的需求仍然存在,所以,在所有的 xaml 体系中,均存在一个代替的控件——Canvas。本文基于 Canvas 来实现控件的拖拉效果。
在整个控件拖拉的过程当中,可以分解为 3 个部分,第一个部分是输入设备点击控件,第二个部分是保持按下的状态下移动输入设备,第三个部分是释放输入设备。那么,就必须对这 3 个过程做出相应的逻辑处理。
那么,有一个重要的问题来了,如何标识控件是否处于拖拉状态。C# 不像 javascript 那样,能够随便修改对象,添加属性。但是,这难不倒微软的工程师,在 xaml 体系中,有附加属性这样一个东西。
public static class DragHelper
{
public static readonly DependencyProperty IsPraggingProperty = DependencyProperty.RegisterAttached("IsDragging", typeof(bool), typeof(DragHelper), new PropertyMetadata(false));
}
这里使用 IsDragging 来标识控件是否处于拖放过程中。
然后接下来我们需要一个初始化的方法来使控件可以拖放。
public static class DragHelper
{
public static bool Dragable(this UIElement control)
{
// TODO
}
}
这里使用扩展方法,使调用方简洁一些。该方法返回一个布尔值,指示是否操作成功。对于控件的父对象为 Canvas 的,我们返回 true,否则返回 false。
public static class DragHelper
{
public static bool Dragable(this UIElement control)
{
if(control==null)
{
throw new ArgumentNullException("control");
}
if(VisualTreeHelper.GetParent(control) is Canvas)
{
// TODO
return true;
}
else
{
return false;
}
}
}
由于控件没有所谓的 Parent 属性,因此我们需要使用可视树来获取父控件。
接下来将一开始的 3 个过程映射到相应的对象事件。
1、输入设备点击控件:UIElement.PointertPressed
2、输入设备移动:Window.Current.CoreWindow.PointerMoved
3、释放输入设备:Window.Current.CoreWindow.PointerReleased
public static bool Dragable(this UIElement control)
{
// null 判断,参考上面
if(VisualTreeHelper.GetParent(control) is Canvas)
{
control.PointerPressed+=(sender,e)=>
{
// 设置控件进入拖放状态。
control.SetValue(IsDraggingProperty, true);
// TODO
};
var coreWindow = Window.Current.CoreWindow;
coreWindow.PointerMoved+=(sender,args)=>
{
if((bool)control.GetValue(IsDraggingProperty))
{
// TODO
}
};
coreWindow.PointerReleased+=(sender,args)=>
{
// TODO
}; return true;
}
else
{
return false;
}
}
接下来,在移动的过程中,我们需要不断设置控件的 Left、Top 这两个 Canvas 的附加属性来达到拖放的效果。可以通过
args.CurrentPoint.Position
来获得输入设备当前的位置。那么每一次设置的位置就等于初始位置加上当次位置。
总体代码:
public static class DragHelper
{
public static readonly DependencyProperty IsDraggingProperty = DependencyProperty.RegisterAttached(
"IsDragging", typeof(bool), typeof(DragHelper), new PropertyMetadata(false)); public static readonly DependencyProperty StartLeftProperty = DependencyProperty.RegisterAttached("StartLeft",
typeof(double), typeof(DragHelper), new PropertyMetadata(0.0d)); public static readonly DependencyProperty StartTopProperty = DependencyProperty.RegisterAttached("StartTop",
typeof(double), typeof(DragHelper), new PropertyMetadata(0.0d)); public static readonly DependencyProperty StartPositionProperty =
DependencyProperty.RegisterAttached("StartPosition", typeof(Point), typeof(DragHelper),
new PropertyMetadata(default(Point))); public static bool Dragable(this UIElement control)
{
if (control == null)
{
throw new ArgumentNullException("control");
}
if (VisualTreeHelper.GetParent(control) is Canvas)
{
control.PointerPressed += (sender, e) =>
{
control.SetValue(IsDraggingProperty, true);
control.SetValue(StartLeftProperty, Canvas.GetLeft(control));
control.SetValue(StartTopProperty, Canvas.GetTop(control));
control.SetValue(StartPositionProperty, e.GetCurrentPoint(null).Position);
};
var coreWindow = Window.Current.CoreWindow;
coreWindow.PointerMoved += (sender, args) =>
{
if ((bool)control.GetValue(IsDraggingProperty))
{
var currentPosition = args.CurrentPoint.Position;
var startPosition = (Point)control.GetValue(StartPositionProperty);
var deltaX = currentPosition.X - startPosition.X;
var deltaY = currentPosition.Y - startPosition.Y;
var startLeft = (double)control.GetValue(StartLeftProperty);
var startTop = (double)control.GetValue(StartTopProperty);
Canvas.SetLeft(control, startLeft + deltaX);
Canvas.SetTop(control, startTop + deltaY);
}
};
coreWindow.PointerReleased += (sender, args) => control.SetValue(IsDraggingProperty, false); return true;
}
else
{
return false;
}
}
}
}
在第一步保存控件相关信息到附加属性当中便于移动状态使用。
效果:

应用:
例如开发一个 ListView 返回顶部的小插件。

由于 Button 会吞掉 PointerPressed 这个事件,因此这里使用了 Border 来模拟。
Border 相关的 xaml 代码:
<Canvas>
<Border x:Name="btn"
Canvas.Left="300"
Canvas.Top="400"
Width="50"
Height="50"
CornerRadius="50"
BorderBrush="Gray"
BorderThickness="3"
Background="Red"
Tapped="Btn_OnTapped">
<TextBlock Text="顶"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="25"
Foreground="Gold" />
</Border>
</Canvas>
ListView 滚回到顶部的代码。
private void Btn_OnTapped(object sender, TappedRoutedEventArgs e)
{
// Lvw 为 ListView 控件。
var item = Lvw.Items.FirstOrDefault();
if (item != null)
{
Lvw.ScrollIntoView(item);
}
}
【WinRT】让控件飞,WinRT 中实现 web 中的 dragable 效果的更多相关文章
- ASP.NET中共有哪几种类型的控件?其中,HTML控件、HTML服务器控件和WEB服务器控件之间有什么区别
ASP.NET的控件包括WEB服务器控件.WEB用户控件.WEB自定义控件.HTML服务器控件和HTML控件.HTML控件.HTML服务器控件和WEB服务器控件之间的区别如下所示.q HTM ...
- 背水一战 Windows 10 (65) - 控件(WebView): 对 WebView 中的内容截图, 通过 Share Contract 分享 WebView 中的被选中的内容
[源码下载] 背水一战 Windows 10 (65) - 控件(WebView): 对 WebView 中的内容截图, 通过 Share Contract 分享 WebView 中的被选中的内容 作 ...
- WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书
原文:WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书 最近项目中使用弹出控件Popup,发现弹出框的对齐方式在不同的系统中存在不同(Popup在win10上是 ...
- 客户端的javascript改变了asp.net webform页面控件的值,后台代码中如何获取修改后的值。
客户端的javascript改变了asp.net webform页面控件的值,后台代码中如何获取修改后的值. 无论是什么的html控件,只要加上了runat="server" ...
- WPF封装控件时 检测是否在设计模式中
原文:WPF封装控件时 检测是否在设计模式中 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/Vblegend_2013/article/detail ...
- 安卓,网页控件,显示网页 Android, web controls, display web pages
安卓,网页控件,显示网页Android, web controls, display web pages 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq ...
- wpf的UserControl用户控件怎么添加到Window窗体中
转载自 http://www.cnblogs.com/shuang121/archive/2013/01/09/2853591.html 我们来新建一个用户控件UserControl1.xaml &l ...
- 解决Select2控件不能在jQuery UI Dialog中不能搜索的bug
本文使用博客园Markdown编辑器进行编辑 1.问题呈现 项目中使用了jQuery UI的Dialog控件,一般用来处理需要提示用户输入或操作的简单页面.逻辑是修改一个广告的图片和标题. 效果截图如 ...
- ActiveX控件打包成Cab置于网页中自动下载安装(转载)
原文出自http://www.iteye.com/topic/110834 [背景] 做过ActiveX控件的朋友都知道,要想把自己做的ActiveX控件功能放在自己的网页上使用,那么用户在客户端就必 ...
随机推荐
- inner outer
left join 是left outer join的简写,left join默认是outer属性的. Inner JoinInner Join 逻辑运算符返回满足第一个(顶端)输入与第二个(底端)输 ...
- switch_to_frame,切换frame框架
页面包含frame/iframe标签,需要先切换到该frame标签,再去定位属于这个frame的元素. 如果要再去定位其他frame的元素,需要回到该frame的上级,定位到要选择的frame,不 ...
- Unity即将内置骨骼动画插件Anima2D
Unity一直在寻找新的方法来帮助开发者,并为他们提供最好的工具.在此我们向大家宣布,Unity将内置流行的骨骼动画插件Anima2D,从2017年1月开始免费供所有Unity开发者使用! 同时也欢迎 ...
- Tree(树链剖分+线段树延迟标记)
Tree http://poj.org/problem?id=3237 Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12 ...
- 【校招面试 之 C/C++】第10题 C++不在构造函数和析构函数中调用虚函数
1.不要在构造函数中调用虚函数的原因 在概念上,构造函数的工作是为对象进行初始化.在构造函数完成之前,被构造的对象被认为“未完全生成”.当创建某个派生类的对象时,如果在它的基类的构造函数中调用虚函数, ...
- python之面向对象之类变量和实例变量
#Auther Bob #--*--conding:utf-8 --*-- #这里的变量全部都是实例变量 class Role(object): def __init__(self,name,role ...
- win7安装SQL2005出现29506错误
解决方法: 假设下载的文件名为SQLServer2005_SSMSEE.msi ,并且放在F盘根目录下, 新建一个文本文件,输入msiexec /i F:\SQLServer2005_SSMSEE.m ...
- postman 使用 - 连接不到接口
- [leetcode]438. Find All Anagrams in a String找出所有变位词
Given a string s and a non-empty string p, find all the start indices of p's anagrams in s. Strings ...
- Go开发之VScode安装
1.找到官网 https://code.visualstudio.com/ 2根据自己机器环境下载 3.下载vscode地址,macos版本 https://vscode.cdn.azure.cn/s ...