zoukankan      html  css  js  c++  java
  • 【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

    来获得输入设备当前的位置。那么每一次设置的位置就等于初始位置加上当次位置。

    总体代码:

     1     public static class DragHelper
     2     {
     3         public static readonly DependencyProperty IsDraggingProperty = DependencyProperty.RegisterAttached(
     4             "IsDragging", typeof(bool), typeof(DragHelper), new PropertyMetadata(false));
     5 
     6         public static readonly DependencyProperty StartLeftProperty = DependencyProperty.RegisterAttached("StartLeft",
     7             typeof(double), typeof(DragHelper), new PropertyMetadata(0.0d));
     8 
     9         public static readonly DependencyProperty StartTopProperty = DependencyProperty.RegisterAttached("StartTop",
    10             typeof(double), typeof(DragHelper), new PropertyMetadata(0.0d));
    11 
    12         public static readonly DependencyProperty StartPositionProperty =
    13             DependencyProperty.RegisterAttached("StartPosition", typeof(Point), typeof(DragHelper),
    14                 new PropertyMetadata(default(Point)));
    15 
    16         public static bool Dragable(this UIElement control)
    17         {
    18             if (control == null)
    19             {
    20                 throw new ArgumentNullException("control");
    21             }
    22             if (VisualTreeHelper.GetParent(control) is Canvas)
    23             {
    24                 control.PointerPressed += (sender, e) =>
    25                 {
    26                     control.SetValue(IsDraggingProperty, true);
    27                     control.SetValue(StartLeftProperty, Canvas.GetLeft(control));
    28                     control.SetValue(StartTopProperty, Canvas.GetTop(control));
    29                     control.SetValue(StartPositionProperty, e.GetCurrentPoint(null).Position);
    30                 };
    31                 var coreWindow = Window.Current.CoreWindow;
    32                 coreWindow.PointerMoved += (sender, args) =>
    33                 {
    34                     if ((bool)control.GetValue(IsDraggingProperty))
    35                     {
    36                         var currentPosition = args.CurrentPoint.Position;
    37                         var startPosition = (Point)control.GetValue(StartPositionProperty);
    38                         var deltaX = currentPosition.X - startPosition.X;
    39                         var deltaY = currentPosition.Y - startPosition.Y;
    40                         var startLeft = (double)control.GetValue(StartLeftProperty);
    41                         var startTop = (double)control.GetValue(StartTopProperty);
    42                         Canvas.SetLeft(control, startLeft + deltaX);
    43                         Canvas.SetTop(control, startTop + deltaY);
    44                     }
    45                 };
    46                 coreWindow.PointerReleased += (sender, args) => control.SetValue(IsDraggingProperty, false);
    47 
    48                 return true;
    49             }
    50             else
    51             {
    52                 return false;
    53             }
    54         }
    55     }
    56 }
    View Code

    在第一步保存控件相关信息到附加属性当中便于移动状态使用。

    效果:

    应用:

    例如开发一个 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);
                }
            }
  • 相关阅读:
    在IIS7中应用Application Request Routing配置反向代理
    sqlite数据类型(时间 日期 ) timestamp 使用
    Windows环境下搭建Redis集群(Redis-x64-3.2.100)
    Vertx上传 官网Demo Java版
    Vert.x HTTP 服务器与客户端
    vertx-mysql-client/java/
    vertx-jersey
    Vertx和Jersey集成使用
    jersey常用注解解释 JAX-RS常用注解:
    Statement及PreparedStatement执行多个sql
  • 原文地址:https://www.cnblogs.com/h82258652/p/4251515.html
Copyright © 2011-2022 走看看