http://www.silverlight.net/blogs/jesseliberty/archive/2009/01/13/drag-and-drop-with-managed-code.aspx
When creating a complex application, I have found that attaching a MouseLeftButtonDown, MouseMove and MouseLeftButtonUp to every object that is dragable is problematic. As an alternative, I use the function VisualTreeHelper.FindElementsInHostCoordinates and manage the process from a parent UI element.
This code sets up mouse up and mouse down events for the parent UI object:
public DrawingSurface() : base()
{
MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
MouseLeftButtonUp += new MouseButtonEventHandler(OnMouseLeftButtonUp);
}
The following code lets me hit test against the children objects in the entire VisualTree, looking for an element of type "T", which are UIElements. During the search I am also looking for a panel of type "C", just in case the user is not over an object (for example, selecting nothing). A list of select objects is returned :
public List<T> FindElement<T,C>(Point oPoint, ref Panel oPanel) where T : UIElement
{
List<T> oList = new List<T>();
foreach (UIElement oElement in VisualTreeHelper.FindElementsInHostCoordinate(oPoint, this))
{
T oShape = oElement as T;
if (oShape != null)
oList.Add(oShape);
if (oElement is C && oPanel == null)
oPanel = oElement as Panel;
}
return oList;
}
Here is just one example of some of the hit test logic you can implement. Based on the type of SketchObject that is found, I can infer the user's drawing need -- is the user planning to drag the shape, stretch the shape, connect the shape, or create the shape -- and auto-select the right drawing tool. It is a lot easier to implement this logic in the parent UI Element:
void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Panel oPanel = null;
Point oPoint = e.GetPosition(null);
CurrentTool = DrawingTool.Ignore;
ActiveHandle = FindElement(oPoint, ref oPanel);
if (ActiveHandle.Count != 0)
{
if (ActiveHandle[0] is RotateHandle)
CurrentTool = DrawingTool.Rotate;
}
ActivePort = FindElement(oPoint,ref oPanel);
if (ActivePort.Count != 0)
{
if (CurrentTool == DrawingTool.Ignore)
CurrentTool = DrawingTool.Connect;
OpenDragConnect(ActivePort[0], oPoint);
return;
}
ActiveGroup = FindElement(oPoint, ref oPanel);
if(ActiveGroup.Count != 0)
{
if ( CurrentTool == DrawingTool.Ignore )
CurrentTool = DrawingTool.Move;
OpenDragDropShape(ActiveGroup[0],oPoint);
return;
}
ActiveMaster = FindElement(oPoint, ref oPanel);
if (ActiveMaster.Count != 0)
{
CurrentTool = DrawingTool.Create;
OpenDragDropShape(ActiveMaster[0], oPoint);
return;
}
}
By using this approach you can consolidate all of drag & drop code in one place, making it easier to manage and maintain.
No comments:
Post a Comment