【WinRT】让控件飞,WinRT 中实现 web 中的 dragable 效果

由于在 xaml 体系中,控件没有传统 WebForm 中的 Left、Top、Right、Bottom 这些属性,取而代之的是按比例(像 Grid)等等的响应布局。但是,传统的这些设置 Left、Top 的硬编码的需求仍然存在,所以,在所有的 xaml 体系中,均存在一个代替的控件——Canvas。本文基于 Canvas 来实现控件的拖拉效果。

在整个控件拖拉的过程当中,可以分解为 3 个部分,第一个部分是输入设备点击控件,第二个部分是保持按下的状态下移动输入设备,第三个部分是释放输入设备。那么,就必须对这 3 个过程做出相应的逻辑处理。

那么,有一个重要的问题来了,如何标识控件是否处于拖拉状态。C# 不像 javascript 那样,能够随便修改对象,添加属性。但是,这难不倒微软的工程师,在 xaml 体系中,有附加属性这样一个东西。

1 public static class DragHelper
2 {
3     public static readonly DependencyProperty IsPraggingProperty = DependencyProperty.RegisterAttached("IsDragging", typeof(bool), typeof(DragHelper), new PropertyMetadata(false));
4 }

这里使用 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 (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 代码:

 1             <Canvas>
 2                 <Border x:Name="btn"
 3                         Canvas.Left="300"
 4                         Canvas.Top="400"
 5                         Width="50"
 6                         Height="50"
 7                         CornerRadius="50"
 8                         BorderBrush="Gray"
 9                         BorderThickness="3"
10                         Background="Red"
11                         Tapped="Btn_OnTapped">
12                     <TextBlock Text="顶"
13                                HorizontalAlignment="Center"
14                                VerticalAlignment="Center"
15                                FontSize="25"
16                                Foreground="Gold" />
17                 </Border>
18             </Canvas>

ListView 滚回到顶部的代码。

        private void Btn_OnTapped(object sender, TappedRoutedEventArgs e)
        {
            // Lvw 为 ListView 控件。
            var item = Lvw.Items.FirstOrDefault();
            if (item != null)
            {
                Lvw.ScrollIntoView(item);
            }
        }
时间: 2024-08-25 10:43:44

【WinRT】让控件飞,WinRT 中实现 web 中的 dragable 效果的相关文章

解决Select2控件不能在jQuery UI Dialog中不能搜索的bug

本文使用博客园Markdown编辑器进行编辑 1.问题呈现 项目中使用了jQuery UI的Dialog控件,一般用来处理需要提示用户输入或操作的简单页面.逻辑是修改一个广告的图片和标题. 效果截图如下: 使用Select2,主要是因为它支持下拉式搜索.所以在数据稍微多一点,作为搜索选择功能的首选.但是运行出来之后,发现搜索框无法点击.开始想到的index不够大,被其他的元素覆盖了.但是跳转z-index也无法解决.在普通的页面,搜索框是ok的. 2.解决办法 通过Google搜索,发现sele

学习IOS开问题篇--视图的模型控件属性写在私有分类中的原因

在说原型模式之前,我们先来看java里面的深复制和浅复制: 1. 浅复制:被复制的对象的所有变量都持有和原来对象的变量相同的值,而所有的对其他对象的引用都指向原来的对象. 2. 深复制:被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他变量的对象.那些引用其他对象的变量将指向被复制过来的新对象,而不是原来那些被引用的对象.深复制需要把要复制的对象的所有引用都复制一遍. 这两者的区别就是关于引用对象的处理,浅复制是不考虑引用对象,而深复制需要考虑引用对象的问题. 对java中的clon

Android 控件的一些属性--持续更新中...

归纳一些冷门又可能用到的Android控件属性 1.ListView android:drawSelectorOnTop="true" 点击某一条记录,颜色会显示在最上面,记录上的文字被遮住,所以点击文字不放,文字就看不到 android:drawSelectorOnTop="false" 点击某条记录不放,颜色会在记录的后面,成为背景色,但是记录内容的文字是可见的 取消分割线/分隔线 android:divider="@null" listvi

ASP.NET中共有哪几种类型的控件?其中,HTML控件、HTML服务器控件和WEB服务器控件之间有什么区别

ASP.NET的控件包括WEB服务器控件.WEB用户控件.WEB自定义控件.HTML服务器控件和HTML控件.HTML控件.HTML服务器控件和WEB服务器控件之间的区别如下所示.q      HTML控件:这完全是浏览器端的HTML标签控件,例如HTML中常见的单选框表单控件,其HTML代码如以下代码所示.<input type="radio" id="Radio1" value="select1" checked="check

控件水平或垂直居中在布局中的问题

直接在linearlayout中设置gravity属性,而不是在控件中设置. 另外设置weight的时候,最好让所有的控件处在一个布局中 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:gravity="center"     android:backgr

WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书

原文:WPF中Popup控件在Win7以及Win10等中的对齐点方式不一样的解决方案 - 简书 最近项目中使用弹出控件Popup,发现弹出框的对齐方式在不同的系统中存在不同(Popup在win10上是弹出在左边,Win7上是弹出在右边).现在记录解决方案于此: 修改弹出菜单相对于相应菜单项是左对齐还是右对齐 // 解决Popup控件在Win7以及Win10等系统中的对齐点方式不一样的问题(以下两种方法均OK) using System.Reflection;    // 方法一 using Sy

安卓,网页控件,显示网页 Android, web controls, display web pages

安卓,网页控件,显示网页Android, web controls, display web pages 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:[email protected] E-mail: 313134555 @qq.com mWebView.loadUrl("https://zhuanlan.zhihu.com/p/28275732"); mWebView.getSettings().setJavaScriptEnabled(true); mWe

最牛WinRT用户界面控件Essential Studio for WinRT

Syncfusion发布了Essential Studio for WinRT ,为构建Windows Store应用程序提供企业级控件.它是用户界面开发控件中最为强大的工具包,包含40多个控件,其中包括可以读写Excel.Word和PDF文档的XlsIO.DocIO和PDF控件等独有的控件,这些都是其它产品没有的. 图表控件包含超过20种图表类型,如折线图.面积图.条形图.气泡图.柱形图.K线图.盘高-盘低图.盘高-盘低-开盘-收盘图.极坐标图.饼图.雷达图.范围面积图.范围柱状图.散点图.堆

MFC里创建FLASH控件,并从内存流中载入SWF

#include <atlbase.h> extern CComModule _Module;      #include <atlcom.h> #include <oleacc.h> #include <comdef.h> #pragma comment(lib,"atl") #pragma comment(lib,"User32.lib") #import "c:\WINDOWS\system32\Mac