从工具箱到画板,让我想起来从百草园到三味书屋,虽然驴嘴不对马口,但是没有下文了。
控件从工具箱到画板的拖动让我想到了tookit中DragDropTarget控件,工具箱好说用ListBox或者TreeView,画板就不知道怎么搞了,于是决定自己做DragDrop。
先贴张图片:
左侧的是一个listbox,右侧红色的是Canvas。创建一个类库DragDropLibrary(这个名不知道好不好听)。
点击左侧的ListBox,然后移动鼠标到右侧红色部分,松开鼠标控件就放到松开的位置,思路就这么简单。
ListBox的Xaml:(Controls = new string[3] { "TextBox", "Button", "TextBlock" };这个是给ListBox的数据,测试。。。)
<ListBox x:Name="ToolBox" ItemsSource="{Binding Controls,Mode=OneTime}">
<ListBox.ItemTemplate>
<DataTemplate >
<TextBlock Text="{Binding}" MouseLeftButtonDown="OnListBoxItemMouseLeftButtonDown" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Item就一个TextBlock,我们要注册MouseLeftButtonDown事件。
在DragDropLibrary中添加一个类:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace DragDropLibrary
{
public static class DragDropManage
{
private static Panel _root, _board;
//Drop
public delegate void Drop(DragDropEventArgs target);
private static Drop _OnDrag;
private static DragDropEventArgs eveArgs;
//鼠标拖动时跟随效果
private static Image _MouseEffert;
/// <summary>
/// 拖动之前调用
/// </summary>
/// <param name="root">根Panel(Children中包含工具箱和画板)</param>
/// <param name="board">画板</param>
public static void Register(Panel root, Panel board)
{
_root = root;
_board = board;
if (_root is Grid)
{
Grid.SetColumnSpan(_MouseEffert, (_root as Grid).ColumnDefinitions.Count+1);
Grid.SetRowSpan(_MouseEffert, (_root as Grid).RowDefinitions.Count+1);
}
}
static DragDropManage()
{
_MouseEffert = new Image();
}
public static void BeginDrag(object sender, MouseButtonEventArgs e, Drop drop)
{
FrameworkElement target = sender as FrameworkElement;
WriteableBitmap bitmap = new WriteableBitmap(target, new TranslateTransform());
_MouseEffert.Source =bitmap;
_MouseEffert.Height = bitmap.PixelHeight;
_MouseEffert.Width = bitmap.PixelWidth;
_root.Children.Add(_MouseEffert);
Point position = e.GetPosition(_root);
_MouseEffert.Margin = new Thickness(position.X, position.Y, 0, 0);
_MouseEffert.HorizontalAlignment = HorizontalAlignment.Left;
_MouseEffert.VerticalAlignment = VerticalAlignment.Top;
_MouseEffert.CaptureMouse();
eveArgs = new DragDropEventArgs(target);
_OnDrag = drop;
_root.MouseMove += OnRootMouseMove;
_root.MouseLeftButtonUp += OnRootMouseLeftButtonUp;
}
private static void Clear()
{
_root.MouseMove -= OnRootMouseMove;
_root.MouseLeftButtonUp -= OnRootMouseLeftButtonUp;
_root.Children.Remove(_MouseEffert);
_OnDrag = null;
eveArgs = null;
}
private static void OnRootMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
eveArgs.Position = e.GetPosition(_board);
_OnDrag(eveArgs);
Clear();
}
private static void OnRootMouseMove(object sender, MouseEventArgs e)
{
Point position = e.GetPosition(_root);
_MouseEffert.Margin = new Thickness(position.X, position.Y, 0, 0);
Point currentPosition = e.GetPosition(_board);
if (currentPosition.X > 0 && currentPosition.X < _board.ActualWidth
&& currentPosition.Y > 0 && currentPosition.Y < _board.ActualHeight)
{
eveArgs.Accept = true;
}
else
{
eveArgs.Accept = false;
}
}
}
}
using System;
using System.Windows;
namespace DragDropLibrary
{
public class DragDropEventArgs : EventArgs
{
public bool Accept { get; set; }
public Point Position { get; internal set; }
public FrameworkElement Target { get; private set; }
public DragDropEventArgs(FrameworkElement target)
{
Target = target;
Position = new Point(0, 0);
}
}
}
这个EventArgs类也一并贴出。
DragDropManage我做成了静态类,我的电脑只有一个鼠标,而且我也没有多点触控的装备,不知道多点触控能不能同时托两个或者更多控件。
在最最最开始,我们需要初始化DragDropLibrary.DragDropManage.Register(LayoutRoot, BoardCanvas);
LayoutRoot这个都知道,就是程序的根容器,BoardCanvas就是上面说的红色的Canvas。
TextBlock鼠标点击事件,这时我们就开始拖动了。Drop1是一个方法,用来当我们松开鼠标时的回调方法。
private void OnListBoxItemMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragDropLibrary.DragDropManage.BeginDrag(sender, e, Drop1);
}
public void Drag1(DragDropLibrary.DragDropEventArgs target)
{
if (target.Accept)
{
string name = (target.Target as TextBlock).Text;
FrameworkElement element = null;
Type type = GetTypeFromString(name);
if (type != null)
{
element = Activator.CreateInstance(type) as FrameworkElement;
if (target.Position != null)
{
Canvas.SetLeft(element, target.Position.X);
Canvas.SetTop(element, target.Position.Y);
}
element.Width = 80;
element.Height = 40;
BoardCanvas.Children.Add(element);
}
}
}
private Type GetTypeFromString(string typeName)
{
Type type = null;
typeName = "System.Windows.Controls." + typeName;
Assembly assembly = Assembly.Load("System.Windows, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e");
type = assembly.GetType(typeName);
return type;
}
在Drop1中Target是ListBox中的TextBlock所以直接转了。
几点说明:
1.DragDropEventArgs中Accept是用来说明,松开鼠标时,当前鼠标的位置是不是落在Canvas中。Position指示当前位置
2.DragDropEventArgs中Target是鼠标点击时的控件。
3.生成控件我是根据名称和程序集,这两个东西获取的,一开始我设想的就是把所有的控件存到Xml文件中,包括他的中文名,全名,以及程序集,这样ListBox中的控件就可以反射出来了。
4.拖动时要在根容器中注册MouseMove事件以及MouseDown。
5.打了个漫长的电话就不知道该说些什么了,今天周五,各位大侠玩的开心。
本人菜鸟一个,刚刚从学校步入社会,还有很多地方需要向大家学习。开博也是为了和大家更好的交流,将自己的小小的代码拿来让大家批评指正。。。。