一起谈.NET技术,Silverlight 拖动复制控件

  Silverlight 拖动复制控件,就是将控件从一个容器中向另一个容器中拖动时,不是移动控件而把该控件到另一个容器中。这种情形在程序中经常遇到,下面是我做的一个拖动复制控件的示例,仅供有这种需求的朋友们参考。

  新建一个 Silverlight 项目命名为 DragAndCopy ,在新建的项目中添加一个Silverlight 用户控件(Silverlight user control)命名为 DragObject。项目结构如下图所示:

  其中 DragObject 就是要拖动的用户控件,DragObject 的 Xaml 代码如下:


<UserControl x:Class="DragAndCopy.DragObject"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Image x:Name="icon" Width="128" Height="128" Stretch="Fill" />
</UserControl>

  这里只是演示拖动复制效果,只在 DragObject 中显示一个图标。DragObject 的后置代码如下:


using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;

namespace DragAndCopy
{
public partial class DragObject : UserControl
{
public DragObject()
{
InitializeComponent();

this.Loaded += new RoutedEventHandler(DragObject_Loaded);
}

/// <summary>
/// 唯一标识一个控件
/// </summary>
public string UUID
{
get;
set;
}

/// <summary>
/// 鼠标点击的位置
/// </summary>
public Point ClickPos
{
get;
set;
}

/// <summary>
/// 图标地址(相对)
/// </summary>
public string ImageUri
{
get;
set;
}

void DragObject_Loaded(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrEmpty(ImageUri))
{
BitmapImage bitmap = new BitmapImage(new Uri(ImageUri, UriKind.Relative));
icon.Source = bitmap;
}
}
}
}

  DragObject 的 UUID 属性用来唯一标识一个 DragObject 实例,在鼠标点击 DragObject 时也是通过 UUID 来判断是进行移动还是复制。ClickPos 属性是鼠标点击 DragObject 的位置,ImageUri 属性是 DragObject 的图标的相对地址。

  接下来在 MainPage 中添加几个 DragObject 的实例,并添加一 Canvas 容器。


<UserControl x:Class="DragAndCopy.MainPage"
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:local="clr-namespace:DragAndCopy"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="160" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0" CornerRadius="5,5,5,5" BorderBrush="Green" BorderThickness="1,1,1,1">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="5,10,5,10">
<local:DragObject ImageUri="icons/chrome.png"
Margin="5,5,5,5"
MouseLeftButtonDown="Handle_MouseLeftButtonDown"
MouseLeftButtonUp="Handle_MouseLeftButtonUp" />
<local:DragObject ImageUri="icons/flock.png"
Margin="5,5,5,5"
MouseLeftButtonDown="Handle_MouseLeftButtonDown"
MouseLeftButtonUp="Handle_MouseLeftButtonUp" />
<local:DragObject ImageUri="icons/galeon.png"
Margin="5,5,5,5"
MouseLeftButtonDown="Handle_MouseLeftButtonDown"
MouseLeftButtonUp="Handle_MouseLeftButtonUp" />
<local:DragObject ImageUri="icons/ie7.png"
Margin="5,5,5,5"
MouseLeftButtonDown="Handle_MouseLeftButtonDown"
MouseLeftButtonUp="Handle_MouseLeftButtonUp" />
<local:DragObject ImageUri="icons/konqueror.png"
Margin="5,5,5,5"
MouseLeftButtonDown="Handle_MouseLeftButtonDown"
MouseLeftButtonUp="Handle_MouseLeftButtonUp" />
<local:DragObject ImageUri="icons/mfirefox.png"
Margin="5,5,5,5"
MouseLeftButtonDown="Handle_MouseLeftButtonDown"
MouseLeftButtonUp="Handle_MouseLeftButtonUp" />
</StackPanel>
</Border>

<Canvas x:Name="rootCanvas" Grid.Row="1" Background="White">

</Canvas>
</Grid>
</UserControl>

  接着实现将 DragObject 从 StackPanel 容器中拖动到 Canvas 容器中时,复制一个 DragObject 到 Canvas 容器。拖动复制这个动作是在 StackPanel 中的 DragObject 上按下鼠标左键,然后将鼠标指针拖动到 Canvas 中后弹起鼠标左键,由此可知 StackPanel 中的 DragObject 需要响应鼠标左键的按下事件,Canvas 需要响应鼠标左键的弹起事件。

  先定义两个变:


private DragObject curDrag;
private bool isMouseCaptured;

  curDrag 是用来保存要复制的控件的中间变量,isMouseCaptured 用来判断是否按鼠标左键。

  事件处理代码如下:


void Handle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)?
{
DragObject dragObj = sender as DragObject;
if (dragObj != null) // 鼠标左键在 DragObject 上按下
{
if (string.IsNullOrEmpty(dragObj.UUID)) // 在控件栏中的 DragObject 上按下
{
// 复制要拖动的控件
curDrag = new DragObject();
curDrag.UUID = Guid.NewGuid().ToString("N"); // 使用 Guid 标识复制的每个控件
curDrag.ImageUri = dragObj.ImageUri;
curDrag.ClickPos = e.GetPosition(dragObj);
}
isMouseCaptured = true;
}
}
void Handle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DragObject dragObj = sender as DragObject;
if (sender is Canvas) // 鼠标左键在容器上弹起
{
if (isMouseCaptured)
{
isMouseCaptured = false;
if (!rootCanvas.Children.Contains(curDrag)) // 复制控件
{
double x = e.GetPosition(rootCanvas).X;
double y = e.GetPosition(rootCanvas).Y;

rootCanvas.Children.Add(new DragObject
{
ImageUri = curDrag.ImageUri,
UUID = curDrag.UUID,
ClickPos = curDrag.ClickPos
});

// 添加控件的鼠标左键按下、弹起事件、设置控件的位置
DragObject obj = rootCanvas.Children.First(ue => (ue as DragObject).UUID == curDrag.UUID) as DragObject;
//obj.MouseMove += Handle_MouseMove;
obj.MouseLeftButtonDown += Handle_MouseLeftButtonDown;

obj.SetValue(Canvas.TopProperty, y - obj.ClickPos.Y);
obj.SetValue(Canvas.LeftProperty, x - obj.ClickPos.X);
}
}
}
}

  有了以上的代码就可以实现用户控件的复制了。接下实现 Canvas 容器中的控件的拖动事件,拖动控件的是在控件上按下鼠标左键,然后移动鼠标,因此控件需要处理鼠标左键按下和鼠标移动事件。处理代码如下:


void Handle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragObject dragObj = sender as DragObject;
if (dragObj != null) // 鼠标左键在 DragObject 上按下
{
dragObj.MouseMove -= Handle_MouseMove;
dragObj.MouseMove += Handle_MouseMove;

mouseVerticalPosition = e.GetPosition(null).Y;
mouseHorizontalPosition = e.GetPosition(null).X;
dragObj.CaptureMouse();
isMouseCaptured = true;
}
}

  鼠标移动事件处理代码如下:


void Handle_MouseMove(object sender, MouseEventArgs e)
{
DragObject item = sender as DragObject;

if (item != null && isMouseCaptured)
{
double deltaV = e.GetPosition(null).Y - mouseVerticalPosition;
double deltaH = e.GetPosition(null).X - mouseHorizontalPosition;
double newTop = deltaV + (double)item.GetValue(Canvas.TopProperty);
double newLeft = deltaH + (double)item.GetValue(Canvas.LeftProperty);

// 设置新位置
item.SetValue(Canvas.TopProperty, newTop);
item.SetValue(Canvas.LeftProperty, newLeft);

// 更新全局变量
mouseVerticalPosition = e.GetPosition(null).Y;
mouseHorizontalPosition = e.GetPosition(null).X;
}
}

  通过以上代码我们实现的拖动复制及移动控件,但是上面的代码还有一些小 Bug, 完整的示例代码请到http://zdd.me/myfiles下载。

时间: 2024-11-05 06:11:49

一起谈.NET技术,Silverlight 拖动复制控件的相关文章

Silverlight 拖动复制控件

Silverlight 拖动复制控件,就是将控件从一个容器中向另一个容器中拖动时,不是移动控件而把该控件到另一个容器中.这种情形在程序中经常遇到,下面是我做的一个拖动复制控件的示例,仅供有这种需求的朋友们参考. 新建一个 Silverlight 项目命名为 DragAndCopy ,在新建的项目中添加一个Silverlight 用户控件(Silverlight user control)命名为 DragObject.项目结构如下图所示: 其中 DragObject 就是要拖动的用户控件,Drag

一起谈.NET技术,asp.net控件开发基础(15)

继续我们的话题吧.自定义控件.如果你还不熟悉自定义控件开发的话,还请看看我以前写了几篇,希望对你有帮助 1.1何处继承 自定义控件一般从以下几个基类(此处不包含数据控件) 一.Control类(所有服务器控件的基类,算是比较底层的类,如果控件功能比较简单,要求不多,可直接继承此类.) 二.WebControl类(标准控件的基类,继承此类,你可以继承其丰富的公共属性,若标准控件中的控件没有你需要的控件,你可以继承此类) 三.CompositeControl 类(2.0新增的类,此类继承自WebCo

一起谈.NET技术,asp.net控件开发基础(13)

1.减轻服务器压力,增加用户体验 服务器功能是强大的,客户端脚本一点也不弱,现在的ajax技术和Atlas技术就是最好的证明,我们总是期待UI有一个好的效果,flash动画给我们带来了很酷的效果,我们至少也可以为我们的服务器控件添加客户端脚本,一方面减少了服务器端的回传,一方面又能为控件提供非常酷的效果.我想我们都很喜欢ATLAS里面很多很酷的控件吧,而且无刷新,服务器控件与客户端脚本交互使用,那会服务器控件变的更加完美. 经过上面的废话,下面我们进入正题 2.简单为服务器控件添加客户端脚本 我

一起谈.NET技术,asp.net控件开发基础(8)

有一些复合控件直接把按钮触发事件所需的事情封装好,另外一种则是自定义事件,更具灵活性,当然这是根据需要设计的.以下会以例子来说明的.下面我们假设我们控件中有两个按钮.以下不列出所有代码,具体可在文章最后下载代码. (1) 直接实现按钮事件 在控件中(以下代码并非实现复合控件)直接实现事件则无需自定义事件,如下代码(如果对数据回传有些不熟悉的话,可先看第三篇,希望对你有帮助) 示例一(只列出局部代码,具体可在文章最后下载代码) void IPostBackEventHandler.RaisePos

一起谈.NET技术,asp.net控件开发基础(1)

asp.net本身提供了很多控件,提供给我们这些比较懒惰的人使用,我认为控件的作用就在此,因为我们不想重复工作,所以要创建它,这个本身便是一个需求的关系,所以学习控件开发很有意思. wrox网站上有本书 Professional ASP.NET 2.0 Server Control and Component Development,现在还没有出版,但网站上放出了代码,所以正好下载过来学习一下. 我看过前几章代码,环环相扣,作者用不同的知识向我们展示同一个效果,所以循序渐进的学下来很有好处.虽然

一起谈.NET技术,ASP.NET控件10个最有用的属性详解

对于微软平台开发人员而言,每天都要和各种ASP.NET控件打交道,本文不打算介绍各种控件的具体使用方法,相反,我只想和大家分享一下ASP.NET控件最有用的10个属性,相信读完本文可提升你的开发技能. 1.ClientIDMode 渲染ASP.NET控件时会自动生成一个ID,当我们在客户端脚本中引用它们时,却会制造不少麻烦,虽然它是命名容器和ID的简单串联,但仍然无法预测生成的ID范围. ASP.NET 4.0使用ClientIDMode属性解决了这个问题,它允许你控制生成这些ID的方法,Cli

一起谈.NET技术,asp.net控件开发基础(2)

或许大家还对为何要重写Render方法存有疑惑,希望大家看看我举的例子,能够明白Render方法和其他两个方法的作用,然后真正明白为何一般情况下只须重写Render方法.我们知道我们每次编写控件时,都需要重写Render方法,我们发现在Control类中很多方法可以重写,但我们没有去重写他们,我们需要遵循一个原则,在需要重载的时候再去重写他们 我们还是先来看看与Render方法相关的两个方法 //RenderControl方法的基本实现 public void RenderControl(Htm

一起谈.NET技术,asp.net控件开发基础(22)

上两篇讨论了如何定义结合数据源控件的数据绑定控件.这次我们一起来看下数据源控件是如何实现的.asp.net2.0已经为我们提供了很多数据源控件,相信大家都用过了,也希望大家对其有所熟悉.关于它能做什么就不说了.下面我们也一起来看看,如何简单的实现. 一.你必须了解的 1.关于数据源控件(DataSourceControl) 虽然表面看来,给数据绑定控件指定DataSourceID属性,数据源控件帮你做了一切工作,其实不然,数据源控件只负责收集与数据交互的相关信息,如:SqlDataSource的

一起谈.NET技术,asp.net控件开发基础(6)

位于WebControls命名空间的style类为顶级样式类.大部分标准控件都拥有其样式属性. 1.下面为设置样式方法 (1)你可以直接设置控件样式 Button1.BackColor = System.Drawing.Color.Red; (2)通过获取web控件的样式集合来设置 Button1.ControlStyle.BackColor = System.Drawing.Color.Red; (3)通过设置样式类,利用WebControl类的ApplyStyle方法来复制非空样式,并改写现