【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

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

总体代码:

【WinRT】让控件飞,WinRT 中实现 web 中的 dragable 效果
 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

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

 

效果:

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

 

应用:

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

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

由于 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);

            }

        }

 

你可能感兴趣的:(drag)