silverlight:对象拖动的优雅解决方案
时间:2022-04-23
本文章向大家介绍silverlight:对象拖动的优雅解决方案,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
对象拖动是一个老生常谈的话题,在SL上要实现对象拖动,一般有三种思路:
一、基于Canvas绝对定位布局的拖动
这种处理方法最简单,修改对象的Canvas.Top与Canvas.Left即可,简单明了!
在线案例: silverlight图片局部放大效果
但是很多时候,我们采用的布局并不是Canvas,如果仅仅为了实现对象拖动,把整个布局重构,代价太大,有点得不偿失。
二、基于对象Margin值的拖动
Margin是对象的通用属性,通过改变Margin值理论上可在任何布局下,重新定位对象的位置。
在线案例: silverlight:类似iBaidu,iGoogle的拖放功能
缺点就是算法处理有些小复杂,初次看着有点晕。
三、基于TranslateTransform偏移量的拖动
每个对象都可以设置一系列RenderTransform,以实现变形、旋转、偏移等多种很Cool的效果。这也是一种通用的做法,不局限于某种特定的布局方法。
而且可以借助Behaviour将其封装起来,直接应用于多个对象,这也是我个人认为最优雅的解决方案。
封装代码如下:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace SLControls
{
public class Drag : Behavior<FrameworkElement>
{
public static readonly DependencyProperty IsMovableProperty =
DependencyProperty.Register("IsMovable", typeof(bool),
typeof(Drag), new PropertyMetadata(null));
[Category("Target Properties")]
public bool IsMovable { get; set; }
private bool _isDragging = false;
private Point _offset;
private readonly TranslateTransform _elementTranslate = new TranslateTransform();
private TranslateTransform _imgTranslate = new TranslateTransform();
private Image _img = new Image();
/// <summary>
/// Drag行为附加到对象上时触发
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += AssociatedObjectLoaded;
//先将对象置于左上角
AssociatedObject.HorizontalAlignment = HorizontalAlignment.Left;
AssociatedObject.VerticalAlignment = VerticalAlignment.Top;
AssociatedObject.MouseLeftButtonDown += AssociatedObjectMouseLeftButtonDown;
}
void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
{
//默认先给对象创建一个TranslateTransform
AssociatedObject.RenderTransform = _elementTranslate;
}
/// <summary>
/// Drag行为从对象剥离时触发
/// </summary>
protected override void OnDetaching()
{
base.OnDetaching();
//移除鼠标左键事件处理
AssociatedObject.MouseLeftButtonDown -= AssociatedObjectMouseLeftButtonDown;
}
/// <summary>
/// 动象拖动时的处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AssociatedObjectMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (!_isDragging) return;
FrameworkElement parent = _img.Parent as FrameworkElement;
Point newPosition = e.GetPosition(parent);
//移动的其实只是对象的"影子副本"
_imgTranslate.X = (newPosition.X - _offset.X);
_imgTranslate.Y = (newPosition.Y - _offset.Y);
}
/// <summary>
/// 托运结束时的处理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AssociatedObjectMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (!_isDragging) return;
Panel panel = AssociatedObject.Parent as Panel;
//停止拖动
_isDragging = false;
//释放鼠标
_img.ReleaseMouseCapture();
//解除事件绑定
_img.MouseMove -= AssociatedObjectMouseMove;
_img.MouseLeftButtonUp -= AssociatedObjectMouseLeftButtonUp;
//如果允许移动,则将"影子Transform"的偏移量赋值给"对象的Transform"
if (IsMovable)
{
_elementTranslate.X = _imgTranslate.X;
_elementTranslate.Y = _imgTranslate.Y;
}
//重新初始化偏移量,同时将对象本身恢复原透明度
_imgTranslate = new TranslateTransform();
_offset = new Point(0, 0);
AssociatedObject.Opacity = 1;
//清除Image
if (panel != null) panel.Children.Remove(_img);
//为下次移动准备一个新的Image
_img = new Image();
}
/// <summary>
/// 开始拖动时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AssociatedObjectMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
_isDragging = true;//处理标志位
AssociatedObject.Opacity = .35;//将对象透明度降低
//生成对象的"位图影子副本"
WriteableBitmap bitmap = new WriteableBitmap(AssociatedObject, new TranslateTransform());
if (_img == null) return;
_img.Source = bitmap;
_img.HorizontalAlignment = HorizontalAlignment.Left;
_img.VerticalAlignment = VerticalAlignment.Top;
_img.Stretch = Stretch.None;
_img.Width = bitmap.PixelWidth;
_img.Height = bitmap.PixelHeight;
_imgTranslate.X = _elementTranslate.X;
_imgTranslate.Y = _elementTranslate.Y;
_img.RenderTransform = _imgTranslate;
//注册鼠标事件,以响应拖动
_img.MouseMove += AssociatedObjectMouseMove;
_img.MouseLeftButtonUp += AssociatedObjectMouseLeftButtonUp;
Panel panel = AssociatedObject.Parent as Panel;
if (panel != null) panel.Children.Add(_img);
_offset = e.GetPosition(_img);
//捕获鼠标,以防止鼠标移动过快时,甩掉"影子对象"
_img.CaptureMouse();
}
}
}
而且很多时候,对象拖动后要求能保存新的位置信息,以方便用户下次进入时,能自动恢复到上次改变过的位置。 示例代码: Xaml部分
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ctl="clr-namespace:SLControls;assembly=SlControls"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" x:Class="slApp.MainPage"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border x:Name="bdr" Cursor="Hand" BorderBrush="#FFC2B529" BorderThickness="10" Background="#FF291313" HorizontalAlignment="Center"
VerticalAlignment="Center" Width="50" Height="50">
<i:Interaction.Behaviors>
<!--一行代码就搞定了拖动!-->
<ctl:Drag IsMovable="True"/>
</i:Interaction.Behaviors>
</Border>
<StackPanel Orientation="Horizontal" Grid.Row="1" Grid.ColumnSpan="2" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button x:Name="btnSave" Click="btnSave_Click" Grid.Column="1" Padding="10,5">保存当前位置</Button>
<Button x:Name="btnLoad" Click="btnLoad_Click" Grid.Row="1" Grid.Column="1" Margin="10,0,0,0" Padding="10,5">加载上次位置</Button>
</StackPanel>
</Grid>
</UserControl>
示例代码:Xaml.cs部分
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace slApp
{
public partial class MainPage : UserControl
{
Point p;
public MainPage()
{
InitializeComponent();
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
TranslateTransform transform = bdr.RenderTransform as TranslateTransform;
if (transform != null)
{
p.X = transform.X;
p.Y = transform.Y;
}
}
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
TranslateTransform transform = bdr.RenderTransform as TranslateTransform;
if (transform != null)
{
transform.X = p.X;
transform.Y = p.Y;
}
}
}
}
四、基于MatrixTransform的拖动
Blend自带的MouseDragElementBehavior,其内部原理就是利用MatrixTransform形成的偏移。
示例源码
http://files.cnblogs.com/yjmyzz/DragElementBehaviorSample.zip
- 微信公众平台快速开发框架 For Core 2.0 beta –JCSoft.WX.Core 5.2.0 beta发布
- Android系统层Watchdog机制源码分析
- 算法之插入排序
- Android Studio环境下搭建ReactNative
- Android实现两个ScrollView互相联动,同步滚动的效果
- 一个可以拖动的自定义Gridview代码
- android图片加载库Glide
- 密码最短长度为7,其中必须包含以下非字母数字字符1 完美解决方案
- android开发性能分析
- url带中文参数显示乱码的问题
- 转换程序的一些问题:设置为 OFF 时,不能为表 'Test' 中的标识列插入显式值。8cad0260
- JQuery 对控件的事件操作
- 流畅地HtmlHelper-Asp.Net MVC
- 用Sql生成数据插入Sql脚本
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python 技术篇-用mutagen库提取MP3歌曲图片
- Python 典藏篇-Microsoft Visual C++ 14.0 is required,官方vc++运行库工具一键式解决!
- Python 技术篇-邮件写入html代码,邮件发送表格,邮件发送超链接,邮件发送网络图片
- 面经手册 · 第11篇《StringBuilder 比 String 快?空嘴白牙的,证据呢!》
- domReady的理解
- Map集合排序
- Chrome 技术篇-一台电脑设置多个独立chrome方法。chrome独立多开技术。
- 023.Ubuntu常见个性化配置
- 快速学习-ElasticJob的FAQ
- 设计模式~状态模式
- 程序员该造轮子吗,造轮子能升职加薪吗?
- 1.基本标签
- 细品mysql之Join 语句的执行过程
- A Java Fork/Join Framework(Doug Lea 关于java Fork/Join框架的论文翻译)
- Mysql 的安装