I am new to GoXam, so bare with me ;-)
I have a Telerik Tree right next to my GoDiagram, and I want to be able to drag in tree elements to create new nodes in my diagram.Are you using Silverlight or WPF?
If you are using WPF:
The easiest implementation strategy is to make sure that the drag-and-drop data is an instance of your model’s node data type.
For example, consider the case where my Diagram.Model was created as an instance of GraphLinksModel<TestData, Object, String, TestLink>. TestData and TestLink are data classes that I have defined. And make sure you have set DiagramModel.Modifiable to true.
Then you could build a TreeView where each TreeViewItem had an instance of TestData associated with it. For this example, I have built the tree in XAML and the TreeViewItem.Header is a TestData.
<TreeView x:Name="myTreeView" SelectedValuePath="Header" MouseMove="myTreeView_MouseMove">
<TreeViewItem Header="Root">
<TreeViewItem>
<TreeViewItem.Header>
<local:TestData Name="First Data" />
</TreeViewItem.Header>
</TreeViewItem>
<TreeViewItem>
<TreeViewItem.Header>
<local:TestData Name="Second Data" />
</TreeViewItem.Header>
</TreeViewItem>
</TreeViewItem>
</TreeView>
(Assume TestData.ToString() returns its Name property, or something like that.)
The drag-and-drop could be started via:
private void myTreeView_MouseMove(object sender, MouseEventArgs e) {
if (e.LeftButton == MouseButtonState.Pressed && myTreeView.SelectedItem != null) {
DragDrop.DoDragDrop(myTreeView, myTreeView.SelectedValue, DragDropEffects.Copy);
}
}
Note that this code depends on TreeView.SelectedValuePath=“Header”, as an easy way of getting the TreeViewItem's header data.
If you also make sure that Diagram.AllowDrop=“True”, I think you’ll find that everything just works.
There’s another example using a ListBox and using multiple data classes in this post.
If you are using Silverlight:
Silverlight doesn’t support drag-and-drop, so there isn’t any built-in support for handling drops from other elements except when copying from another Diagram. (Well, Silverlight 4 supports a very restricted form of drag-and-drop, but that doesn’t help either of us.)
I’m not familiar with Telerik’s drag-and-drop mechanism in Silverlight. You’ll need to implement your own drop handler, because Diagram.ExternalObjectsDropped won’t be involved.
There is “common” drag-and-drop support in the Silverlight Toolkit from silverlight.codeplex.com. I know that that works with GoXam, from TreeViews to Diagram. But the caution is that this functionality is considered “Experimental” by Microsoft.
OK, I have tried the Silverlight toolkit’s drag-and-drop support for TreeViews. I purposely used the older Silverlight 3 toolkit from November 2009, to make sure this stuff works in Silverlight 3 and (presumably) also with the toolkit for Silverlight 4.
Here are the XMLNS declarations, which work in Silverlight 3 or 4:
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
xmlns:mswindows="clr-namespace:Microsoft.Windows;assembly=System.Windows.Controls.Toolkit"
Note the use of two DLLs, System.Windows.Controls.DLL for TreeView and System.Windows.Controls.Toolkit.DLL for drag-and-drop support.
Here’s the TreeView:
<toolkit:TreeViewDragDropTarget Grid.Column="0"
mswindows:DragDrop.AllowDrop="False"
AllowedSourceEffects="Copy"
ItemDroppedOnTarget="TreeViewDragDropTarget_ItemDroppedOnTarget">
<controls:TreeView x:Name="myTreeView"
SelectedValuePath="Header">
<controls:TreeViewItem Header="Root">
<controls:TreeViewItem>
<controls:TreeViewItem.Header>
<local:TestData Key="First Data" />
</controls:TreeViewItem.Header>
</controls:TreeViewItem>
<controls:TreeViewItem>
<controls:TreeViewItem.Header>
<local:TestData Key="Second Data" />
</controls:TreeViewItem.Header>
</controls:TreeViewItem>
</controls:TreeViewItem>
</controls:TreeView>
</toolkit:TreeViewDragDropTarget>
The Diagram is declared like:
<go:Diagram x:Name="myDiagram" Grid.Column="1"
mswindows:DragDrop.AllowDrop="True"
. . . />
And the ItemDroppedOnTarget event handler:
private void TreeViewDragDropTarget_ItemDroppedOnTarget(object sender, ItemDragEventArgs e) {
var coll = e.Data as SelectionCollection;
if (coll != null) {
myDiagram.StartTransaction("Dropped data");
foreach (Selection sel in coll) {
var item = sel.Item as TreeViewItem;
if (item != null) {
var data = item.Header as TestData;
if (data != null) {
var newdata = myDiagram.Model.AddNodeCopy(data) as TestData;
if (newdata != null) newdata.Location = myDiagram.LastMousePointInModel;
}
}
}
myDiagram.CommitTransaction("Dropped data");
}
}
Of course you’ll need to customize the code for your own data.
3. Drop target is managed via mouse_enter,mouse_leave events.
<UserControl.Resources>
<DataTemplate x:Key="yourResouceKey">
<toolkit:ListBoxDragDropTarget ItemDroppedOnTarget="ListBoxDragDropTarget_ItemDroppedOnTarget">
<ListBox
ItemsSource="{Binding Mode=OneWay}"
Style="{StaticResource AccordionListBoxStyle}"
ItemContainerStyle="{StaticResource DraggableItemStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name, Mode=OneWay}" Margin="0,3" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</toolkit:ListBoxDragDropTarget></DataTemplate>
C#
Drop Event:
private void ListBoxDragDropTarget_ItemDroppedOnTarget(object sender, System.Windows.Controls.ItemDragEventArgs e)
{
SelectionCollection selectionCollection = e.Data as SelectionCollection;
Selection sel = selectionCollection[0];
if (sel != null && Globals.Instance.ActiveSpotPanel != null)
{
e.Handled = ProcessDrop(Globals.Instance.ActiveSpotPanel, Globals.Instance.ActiveNode, sel.Item);
}
else
{
e.Handled = true;
}
}
Event Handling and process:
private bool ProcessDrop(Northwoods.GoXam.SpotPanel sp,Northwoods.GoXam.Node node, object Data)
{
bool dropMatch = false;
bool handled = false;
MyNodeObjectnodeData = (MyNodeObject)node.Data as MyNodeObject;
if (Data is Document)
{
Document payload = Data as Document;
dropMatch = SetDocumentNode(ref nodeData, payload);
if (!dropMatch) { ShowDropError(nodeData.Type, "document"); }
handled = true;
}return handled;}MyNodeObject is a class that is associated as the Data Context of each node
These are the events that are used to store the drop target in a static Globals class.
private void Node_MouseEnter(object sender, MouseEventArgs e)
{
if (Globals.Instance.DiagramMode == DiagramMode.Design)
{
SetTagVisible(sender as UIElement, true);
}
}
// Sets the Tag property on a Node object to false
// when the MouseEnter event is called on the Node's SpotPanel.
// The binding on the Stroke will change to a Transparent brush.
private void Node_MouseLeave(object sender, MouseEventArgs e)
{
SetTagVisible(sender as UIElement, false);
}
// Used in the above two methods to change the node's Tag property to a specified value.
private void SetTagVisible(UIElement uielement, bool visible)
{
if (Northwoods.GoXam.Part.FindAncestor<Palette>(uielement) == null)
{
SpotPanel sp = uielement as SpotPanel;
if (sp == null) return;
Node n = Northwoods.GoXam.Part.FindAncestor<Node>(sp);
if (n == null) return;
n.Tag = visible;
if (visible)
{
Globals.Instance.ActiveNode = n;
Globals.Instance.ActiveSpotPanel = sp;
}
else
{
Globals.Instance.ActiveNode = null;
Globals.Instance.ActiveSpotPanel = null;
}
}
}
Enjoy
Thanks for the additional sample code.