Created
January 15, 2012 17:51
-
-
Save ido-ran/1616572 to your computer and use it in GitHub Desktop.
GoWPF 1.3.1.4 Drag and Drop Issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright © Northwoods Software Corporation, 2008-2011. All Rights Reserved. */ | |
using System; | |
using System.Collections.Generic; | |
using System.Globalization; | |
using System.Windows; | |
using System.Windows.Controls; | |
using System.Windows.Input; | |
using System.Xml.Linq; | |
using Northwoods.GoXam; | |
using Northwoods.GoXam.Model; | |
using Northwoods.GoXam.Tool; | |
using System.Diagnostics; | |
namespace FlowChart { | |
public partial class FlowChart : UserControl { | |
public FlowChart() { | |
InitializeComponent(); | |
// use custom tools and PartManager; these could have been defined in XAML also | |
myDiagram.PartManager = new MyPartManager(); | |
myDiagram.LinkingTool = new MyLinkingTool(); | |
myDiagram.RelinkingTool = new MyRelinkingTool(); | |
myDiagram.DraggingTool = new MyDraggingTool(); | |
myDiagram.AllowDrop = true; | |
// set up the model for the Palette | |
var paletteModel = new GraphLinksModel<MyNodeData, String, String, MyLinkData>(); | |
paletteModel.DataFormat = "HelloDataFormat"; | |
// this creates the palette's model's data in code: | |
paletteModel.NodesSource = new List<MyNodeData>() { | |
new MyNodeData() { Key="Comment", Text="Comment", Category="Comment", Figure=NodeFigure.Rectangle }, | |
new MyNodeData() { Key="Start", Text="Start", Category="Start", Figure=NodeFigure.RoundedRectangle }, | |
new MyNodeData() { Key="Step", Text="Step", Category="Standard", Figure=NodeFigure.Rectangle }, | |
new MyNodeData() { Key="Input", Text="Input", Category="Standard", Figure=NodeFigure.Input }, | |
new MyNodeData() { Key="Output", Text="Output", Category="Standard", Figure=NodeFigure.Output }, | |
new MyNodeData() { Key="Conditional", Text="?", Category="Standard", Figure=NodeFigure.Diamond }, | |
new MyNodeData() { Key="Read", Text="Read", Category="Standard", Figure=NodeFigure.Ellipse }, | |
new MyNodeData() { Key="Write", Text="Write", Category="Standard", Figure=NodeFigure.Ellipse }, | |
new MyNodeData() { Key="ManualOperation", Text="Manual Operation", Category="Standard", Figure=NodeFigure.ManualOperation }, | |
new MyNodeData() { Key="DataBase", Text="DataBase", Category="Standard", Figure=NodeFigure.Database }, | |
new MyNodeData() { Key="End", Text="End", Category="End", Figure=NodeFigure.RoundedRectangle } | |
}; | |
myPalette.Model = paletteModel; | |
// set up an initial model for the Diagram | |
var model = new GraphLinksModel<MyNodeData, String, String, MyLinkData>(); | |
// and initialize it from the XML file that is an embedded resource | |
String xml = Demo.MainPage.Instance.LoadText("FlowChart", "xml"); | |
model.Load<MyNodeData, MyLinkData>(XElement.Parse(xml), "MyNodeData", "MyLinkData"); | |
model.Modifiable = true; | |
model.HasUndoManager = true; | |
myDiagram.Model = model; | |
} | |
// Sets the Tag property on a Node object to true | |
// when the MouseEnter event is called on the Node's SpotPanel. | |
// The binding on the Stroke will change to a Black brush. | |
private void Node_MouseEnter(object sender, MouseEventArgs e) { | |
SetPortsVisible(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) { | |
SetPortsVisible(sender as UIElement, false); | |
} | |
// Used in the above two methods to change the node's Tag property to a specified value. | |
private void SetPortsVisible(UIElement uielement, bool visible) { | |
if (Part.FindAncestor<Palette>(uielement) == null) { | |
SpotPanel sp = uielement as SpotPanel; | |
if (sp == null) return; | |
Node n = Part.FindAncestor<Node>(sp); | |
if (n == null) return; | |
n.Tag = visible; | |
} | |
} | |
// save and load the model data as XML, visible in the "Saved" tab of the Demo | |
private void Save_Click(object sender, RoutedEventArgs e) { | |
var model = myDiagram.Model as GraphLinksModel<MyNodeData, String, String, MyLinkData>; | |
if (model == null) return; | |
XElement root = model.Save<MyNodeData, MyLinkData>("FlowChart", "MyNodeData", "MyLinkData"); | |
Demo.MainPage.Instance.SavedXML = root.ToString(); | |
LoadButton.IsEnabled = true; | |
model.IsModified = false; | |
} | |
private void Load_Click(object sender, RoutedEventArgs e) { | |
var model = myDiagram.Model as GraphLinksModel<MyNodeData, String, String, MyLinkData>; | |
if (model == null) return; | |
myDiagram.PartManager.UpdatesRouteDataPoints = false; // tell the MyPartManager that we're loading | |
try { | |
XElement root = XElement.Parse(Demo.MainPage.Instance.SavedXML); | |
// set the Route.Points after nodes have been built and the layout has finished | |
myDiagram.LayoutCompleted += LoadLinkRoutes; | |
model.Load<MyNodeData, MyLinkData>(root, "MyNodeData", "MyLinkData"); | |
} catch (Exception ex) { | |
MessageBox.Show(ex.ToString()); | |
} | |
model.IsModified = false; | |
} | |
// no data-binding of Route.Points means we have to copy the Points data explicitly | |
private void LoadLinkRoutes(Object s, EventArgs e) { | |
// just set the Route points once per Load | |
myDiagram.LayoutCompleted -= LoadLinkRoutes; | |
foreach (Link link in myDiagram.Links) { | |
var d = link.Data as MyLinkData; | |
if (d == null || d.Points == null) continue; | |
link.Route.Points = (IList<Point>)d.Points; | |
} | |
myDiagram.PartManager.UpdatesRouteDataPoints = true; // OK for MyPartManager to update MyLinkData.Points automatically | |
} | |
} | |
// The data class representing nodes. | |
#if !SILVERLIGHT | |
[Serializable] | |
#endif | |
public class MyNodeData : GraphLinksModelNodeData<String> { | |
// The shape of each node | |
public NodeFigure Figure { | |
get { return _Figure; } | |
set { | |
if (_Figure != value) { | |
NodeFigure old = _Figure; | |
_Figure = value; | |
RaisePropertyChanged("Figure", old, value); | |
} | |
} | |
} | |
private NodeFigure _Figure = NodeFigure.Rectangle; | |
// note that adding properties here means also adding lines to MakeXElement and LoadFromXElement | |
public override XElement MakeXElement(XName n) { | |
XElement e = base.MakeXElement(n); | |
e.Add(XHelper.AttributeEnum<NodeFigure>("Figure", this.Figure, NodeFigure.Rectangle)); | |
return e; | |
} | |
public override void LoadFromXElement(XElement e) { | |
base.LoadFromXElement(e); | |
this.Figure = XHelper.ReadEnum<NodeFigure>("Figure", e, NodeFigure.Rectangle); | |
} | |
} | |
// The data class representing links. Actually, there's nothing to add to the predefine link data class. | |
#if !SILVERLIGHT | |
[Serializable] | |
#endif | |
public class MyLinkData : GraphLinksModelLinkData<String, String> { | |
public MyLinkData() { | |
this.Text = "Yes"; | |
} | |
// note that adding properties here means also overriding MakeXElement and LoadFromXElement | |
} | |
// Augment the normal process of adding nodes to the diagram by adjusting the position | |
// of the left and right ports of those nodes showing figures that have slanted sides. | |
// An alternative is to use a different DataTemplate for nodes with these kinds of figures. | |
public class MyPartManager : PartManager { | |
public MyPartManager() { | |
this.UpdatesRouteDataPoints = true; // call UpdateRouteDataPoints when Link.Route.Points has changed | |
} | |
protected override void OnNodeAdded(Node node) { | |
base.OnNodeAdded(node); | |
MyNodeData data = node.Data as MyNodeData; | |
if (data == null) return; | |
// look at the node's Figure | |
switch (data.Figure) { | |
case NodeFigure.Input: | |
case NodeFigure.Output: | |
case NodeFigure.ManualOperation: { | |
FrameworkElement leftport = node.FindPort("2", false); | |
if (leftport != null) SpotPanel.SetSpot(leftport, new Spot(0.05, 0.5, 1, 0)); | |
FrameworkElement rightport = node.FindPort("3", false); | |
if (rightport != null) SpotPanel.SetSpot(rightport, new Spot(0.95, 0.5, -1, 0)); | |
break; | |
} | |
default: break; | |
} | |
} | |
// this supports undo/redo of link route reshaping | |
protected override void UpdateRouteDataPoints(Link link) { | |
if (!this.UpdatesRouteDataPoints) return; // in coordination with Load_Click and LoadLinkRoutes, above | |
MyLinkData data = link.Data as MyLinkData; | |
if (data != null) { | |
data.Points = new List<Point>(link.Route.Points); | |
} | |
} | |
} | |
public class MyDraggingTool : DraggingTool { | |
protected override bool MayCopyExternal(DragEventArgs e) { | |
bool baseResult = base.MayCopyExternal(e); | |
return true; | |
} | |
public override void DoDragOver(DragEventArgs e) { | |
base.DoDragOver(e); | |
Debug.WriteLine("DoDragOver " + e.Effects); | |
} | |
public override void DoDrop(DragEventArgs e) { | |
base.DoDrop(e); | |
} | |
} | |
// Overrides the default LinkingTool to make the Ports appear and disappear when linking begins and ends. | |
public class MyLinkingTool : LinkingTool { | |
// set the Tag property of every Node in the LinkingTool.Diagram.Nodes to true. | |
public override void DoStart() { | |
SetAllNodesPortsVisible(true); | |
base.DoStart(); | |
} | |
// set the Tag property of every Node in the LinkingTool.Diagram.Nodes to false. | |
public override void DoStop() { | |
base.DoStop(); | |
SetAllNodesPortsVisible(false); | |
} | |
// Sets the Tag property of all Nodes in this.Diagram.Nodes to the bool parameter. | |
private void SetAllNodesPortsVisible(bool visibility) { | |
foreach (Node n in this.Diagram.Nodes) { | |
n.Tag = visibility; | |
} | |
} | |
public override bool IsValidLink(Node fromnode, FrameworkElement fromport, Node tonode, FrameworkElement toport) { | |
if (!base.IsValidLink(fromnode, fromport, tonode, toport)) return false; | |
// don't allow a link directly from Start to End | |
MyNodeData fromnodedata = fromnode.Data as MyNodeData; | |
MyNodeData tonodedata = tonode.Data as MyNodeData; | |
if (fromnodedata != null && fromnodedata.Category == "Start" && | |
tonodedata != null && tonodedata.Category == "End") return false; | |
return true; | |
} | |
} | |
// Overrides the default RelinkingTool to make the Ports appear and disappear when linking begins and ends. | |
public class MyRelinkingTool : RelinkingTool { | |
// set the Tag property of every Node in the LinkingTool.Diagram.Nodes to true. | |
public override void DoStart() { | |
SetAllNodesPortsVisible(true); | |
base.DoStart(); | |
} | |
// set the Tag property of every Node in the LinkingTool.Diagram.Nodes to false. | |
public override void DoStop() { | |
base.DoStop(); | |
SetAllNodesPortsVisible(false); | |
} | |
// Sets the Tag property of all Nodes in this.Diagram.Nodes to the bool parameter. | |
private void SetAllNodesPortsVisible(bool visibility) { | |
foreach (Node n in this.Diagram.Nodes) { | |
n.Tag = visibility; | |
} | |
} | |
public override bool IsValidLink(Node fromnode, FrameworkElement fromport, Node tonode, FrameworkElement toport) { | |
if (!base.IsValidLink(fromnode, fromport, tonode, toport)) return false; | |
// don't allow a link directly from Start to End | |
MyNodeData fromnodedata = fromnode.Data as MyNodeData; | |
MyNodeData tonodedata = tonode.Data as MyNodeData; | |
if (fromnodedata != null && fromnodedata.Category == "Start" && | |
tonodedata != null && tonodedata.Category == "End") return false; | |
return true; | |
} | |
} | |
// link labels are visible when they come from a "Conditional" node | |
public class LabelVisibilityConverter : Converter { | |
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) { | |
Link link = value as Link; | |
if (link != null && link.FromNode != null) { | |
MyNodeData d = link.FromNode.Data as MyNodeData; | |
if (d != null && d.Key.StartsWith("Conditional")) return Visibility.Visible; | |
} | |
return Visibility.Collapsed; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment