Silverlight智能表单(2)从工具箱到画板
时间:2011-01-21 来源:无名菜鸟
控件从工具箱到画板的拖动让我想到了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.打了个漫长的电话就不知道该说些什么了,今天周五,各位大侠玩的开心。
本人菜鸟一个,刚刚从学校步入社会,还有很多地方需要向大家学习。开博也是为了和大家更好的交流,将自己的小小的代码拿来让大家批评指正。。。。