This commit is contained in:
panthernet 2015-11-02 18:03:43 +03:00
Родитель 199b9c299c
Коммит 271ca09de3
29 изменённых файлов: 447 добавлений и 59 удалений

Просмотреть файл

@ -5,6 +5,11 @@ HIGHLIGHTS:
Currently there are two modes supoported:
- Layout groups to predefined bounds, when you can specify rectangular bounds in which vertices are layed (Bounds must be supported by algorithm used to layout vertices group)
- Generate bounds from groups, when each group is layouted using its algorithm and bounds are automatically calculated to fit all vertices in the group and then group bounds overlaps can be removed.
* Added two new label controls AttachedEdgeLabelControl and AttachedVertexLabelControl which acts like separate entities in GraphArea visual tree and have weak references to graphx controls. Default EdgeLableControl and VertexLabelControl are designed to act as the part of their parent classes and this approach impacts their customization possibilities when these parent classes are limited in size. So with the new labels you can mitigate following restrictions:
- No more label cuts when vertex is strictly limited in width or height
- No more jerky edge endpoints when edge label is too large
- No more labels behind edges or vertices. You can control how to inject them.
To use new labels you have to add them using to GraphArea::AddCustomChildControl() method and assign either VertexControl or EdgeControl for them using label::Attach() method.
DETAILED CHANGELOG:
+ Added GroupId property to IGraphXVertex interface
@ -12,10 +17,16 @@ DETAILED CHANGELOG:
+ Added two methods to EdgeControl: GetEdgePointerForSource() and GetEdgePointerForTarget() which allows to get to edge pointer objects manualy
+ Added VertexShape.Ellipse math shape
+ Added support for reversing the geometry. This is required for animating shapes along a path where the direction needs to be reversed without using the Storyboard.AutoReverse property (thanks to bleibold)
+ Added two new attached label classes for Edge and Vertex controls.
+ Added EdgeControl::LabelMouseDown event
+ Added separate ID counter for edges while autoresolving missing id
+ Added EdgeControl.UpdateLabel() method to be able to update attached edge label manually (tech means to overcome some template quizes)
+ Fixed an exception in ZoomControl caused by Ctrl + Alt + DblClick combination (thanks to persalmi)
+ Fixed NaN result for FR algorithms calc (thanks to bleibold)
+ Fixed edge bundling in the case when empty Control points are present that would sometimes cause exceptions.(thanks to bleibold)
+ Fixed bindings to DefaultEdgePointer::Visibility property
+ Fixed numerous event issues with graphX controls where events wasn't passed down the hierarchy tree
+ Improved styles flexibility by working with dependency values instead of straight assignment in some places
+ Improved overall graph cleaning in different areas allowing to easily clean graph data and fix potentional memory leaks
+ Improved random layout algorithm randomness by seeding new Guid hash whcih fixes some odd behaviour in rare cases
+ Implemented edge cut logic for EdgePointer placed at edge 'source' to gain better visual quality like its 'target' counterpart
@ -25,6 +36,7 @@ DETAILED CHANGELOG:
BREAKING CHANGES:
* IExternalLayoutAlgorithm interface now demands TEdge generic specification and have one new method ResetGraph().
* All built-in algorithms now use IMutableVertexAndEdgeSet<TVertex, TEdge> for TGraph generic specification to be able to modify Graph data on demand.
* Made Vertex and Edge ID Int64 be default. Was Int32.
RELEASE 2.2.0

Просмотреть файл

@ -11,6 +11,8 @@ namespace ShowcaseApp.WPF
public int Age { get; set; }
public int ImageId { get; set; }
public bool IsBlue { get; set; }
#region Calculated or static props
public override string ToString()

Просмотреть файл

@ -190,6 +190,7 @@ namespace ShowcaseApp.WPF.Pages
{
CreateNewArea();
dg_Area.LogicCore.Graph = ShowcaseHelper.GenerateDataGraph(5, false);
dg_Area.LogicCore.Graph.Vertices.First().IsBlue = true;
var vlist = dg_Area.LogicCore.Graph.Vertices.ToList();
dg_Area.LogicCore.Graph.AddEdge(new DataEdge(vlist[0], vlist[1]) { ArrowTarget = true});
dg_Area.LogicCore.Graph.AddEdge(new DataEdge(vlist[0], vlist[2]) { ArrowTarget = true });

Просмотреть файл

@ -20,17 +20,33 @@
<Style TargetType="{x:Type controls:VertexControl}">
<Setter Property="Background" Value="Yellow"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:VertexControl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" Width="20" Height="20" BorderThickness="1">
BorderBrush="{TemplateBinding BorderBrush}" Width="20" Height="20" BorderThickness="1">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsBlue}" Value="True">
<DataTrigger.Setters>
<Setter Property="Background" Value="Blue"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:VertexControl}">
<Ellipse Width="50" Height="50" Fill="{TemplateBinding Background}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
<controls:VisibilityToBoolConverter x:Key="VisibilityToBoolConverter" Inverted="True" />
<controls:VisibilityToBoolConverter x:Key="VisibilityToBoolConverterNot" Inverted="True" Not="True"/>

Просмотреть файл

@ -2,6 +2,7 @@
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Shapes;
using GraphX.Controls.Models;
@ -63,6 +64,20 @@ namespace GraphX.Controls
((EdgeControl)d).ActivateTargetListener();
}
public event EdgeLabelEventHandler LabelMouseDown;
protected void OnLabelMouseDown(MouseButtonEventArgs mArgs, ModifierKeys keys)
{
if (LabelMouseDown != null)
LabelMouseDown(this, new EdgeLabelSelectedEventArgs(EdgeLabelControl, this, mArgs, keys));
}
protected override void OnEdgeLabelUpdated()
{
if (EdgeLabelControl is Control)
((Control) EdgeLabelControl).MouseDown += (sender, args) => OnLabelMouseDown(args, Keyboard.Modifiers);
}
public object TargetObj { get { return Target; } }
#region public Clean()
public override void Clean()

Просмотреть файл

@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.Windows.Input;
using GraphX.Controls.Models;
using GraphX.PCL.Common.Enums;
using GraphX.PCL.Common.Exceptions;
@ -40,6 +41,8 @@ namespace GraphX.Controls
#region Properties & Fields
public abstract bool IsSelfLooped { get; protected set; }
public abstract void Dispose();
public abstract void Clean();
@ -318,10 +321,11 @@ namespace GraphX.Controls
/// </summary>
protected Path LinePathObject;
private IEdgeLabelControl _edgeLabelControl;
/// <summary>
/// Templated label control to display labels
/// </summary>
protected IEdgeLabelControl EdgeLabelControl;
protected IEdgeLabelControl EdgeLabelControl { get { return _edgeLabelControl; } set { _edgeLabelControl = value; OnEdgeLabelUpdated(); } }
protected IEdgePointer EdgePointerForSource;
protected IEdgePointer EdgePointerForTarget;
@ -364,6 +368,21 @@ namespace GraphX.Controls
set { SetValue(EdgeProperty, value); }
}
internal void InjectEdgeLable(IEdgeLabelControl ctrl)
{
EdgeLabelControl = ctrl;
UpdateLabelLayout();
}
/// <summary>
/// Update edge label if any
/// </summary>
public void UpdateLabel()
{
if(_edgeLabelControl != null && ShowLabel)
UpdateLabelLayout(true);
}
#endregion
#region Position methods
@ -445,6 +464,9 @@ namespace GraphX.Controls
{
get { return LinePathObject != null; }
}
protected virtual void OnEdgeLabelUpdated() { }
#if WPF
public override void OnApplyTemplate()
#elif METRO
@ -461,7 +483,8 @@ namespace GraphX.Controls
if (this.FindDescendantByName("PART_edgeArrowPath") != null)
throw new GX_ObsoleteException("PART_edgeArrowPath is obsolete! Please use new DefaultEdgePointer object in your EdgeControlBase template!");
EdgeLabelControl = GetTemplatePart("PART_edgeLabel") as IEdgeLabelControl;
EdgeLabelControl = EdgeLabelControl ?? GetTemplatePart("PART_edgeLabel") as IEdgeLabelControl;
EdgePointerForSource = GetTemplatePart("PART_EdgePointerForSource") as IEdgePointer;
EdgePointerForTarget = GetTemplatePart("PART_EdgePointerForTarget") as IEdgePointer;
@ -472,7 +495,7 @@ namespace GraphX.Controls
{
if (SelfLoopIndicator != null) SelfLoopIndicator.Arrange(_selfLoopedEdgeLastKnownRect);
};
var x = this.ShowLabel;
MeasureChild(EdgePointerForSource as UIElement);
MeasureChild(EdgePointerForTarget as UIElement);
MeasureChild(SelfLoopIndicator);
@ -784,7 +807,8 @@ namespace GraphX.Controls
if (gEdge.ReversePath)
routePoints.Reverse();
var pcol = new PointCollection(routePoints);
var pcol = new PointCollection();
routePoints.ForEach(a=> pcol.Add(a));
lineFigure = new PathFigure { StartPoint = p1, Segments = new PathSegmentCollection { new PolyLineSegment { Points = pcol } }, IsClosed = false };
}
@ -848,10 +872,10 @@ namespace GraphX.Controls
EdgeLabelControl.SetSize(rect);
}
internal virtual void UpdateLabelLayout()
internal virtual void UpdateLabelLayout(bool force = false)
{
EdgeLabelControl.Show();
if (EdgeLabelControl.GetSize() == SysRect.Empty)
if (EdgeLabelControl.GetSize() == SysRect.Empty || force)
{
EdgeLabelControl.UpdateLayout();

Просмотреть файл

@ -0,0 +1,51 @@

#if WPF
using System.Windows;
using System.Windows.Controls;
using DefaultEventArgs = System.EventArgs;
#elif METRO
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using DefaultEventArgs = System.Object;
#endif
using GraphX.PCL.Common.Exceptions;
namespace GraphX.Controls
{
#if METRO
[Bindable]
#endif
public class AttachableEdgeLabelControl : EdgeLabelControl
{
public EdgeControl AttachNode { get { return (EdgeControl) GetValue(AttachNodeProperty); } private set {SetValue(AttachNodeProperty, value);} }
public static readonly DependencyProperty AttachNodeProperty = DependencyProperty.Register("AttachNode", typeof(EdgeControl), typeof(AttachableEdgeLabelControl),
new PropertyMetadata(null));
public AttachableEdgeLabelControl()
{
DataContext = this;
}
public void Attach(EdgeControl node)
{
AttachNode = node;
node.InjectEdgeLable(this);
}
protected override EdgeControl GetEdgeControl(DependencyObject parent)
{
if(AttachNode == null)
throw new GX_InvalidDataException("AttachableEdgeLabelControl node is not attached!");
return AttachNode;
}
/* public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// var container = Template.FindName("PART_container", this) as ContentPresenter;
//container.Content = AttachNode.Vertex;
}*/
}
}

Просмотреть файл

@ -111,7 +111,7 @@ namespace GraphX.Controls
private EdgeControl _edgeControl;
private static EdgeControl GetEdgeControl(DependencyObject parent)
protected virtual EdgeControl GetEdgeControl(DependencyObject parent)
{
while (parent != null)
{
@ -125,12 +125,20 @@ namespace GraphX.Controls
public void Show()
{
if (EdgeControl.IsSelfLooped && !DisplayForSelfLoopedEdges) return;
#if WPF
SetCurrentValue(UIElement.VisibilityProperty, Visibility.Visible);
#else
SetValue(UIElement.VisibilityProperty, Visibility.Visible);
#endif
}
public void Hide()
{
#if WPF
SetCurrentValue(UIElement.VisibilityProperty, Visibility.Collapsed);
#else
SetValue(UIElement.VisibilityProperty, Visibility.Collapsed);
#endif
}

Просмотреть файл

@ -53,12 +53,20 @@ namespace GraphX.Controls
public void Show()
{
#if WPF
SetCurrentValue(UIElement.VisibilityProperty, Visibility.Visible);
#else
SetValue(UIElement.VisibilityProperty, Visibility.Visible);
#endif
}
public void Hide()
{
#if WPF
SetCurrentValue(UIElement.VisibilityProperty, Visibility.Collapsed);
#else
SetValue(UIElement.VisibilityProperty, Visibility.Collapsed);
#endif
}
private static EdgeControl GetEdgeControl(DependencyObject parent)

Просмотреть файл

@ -348,7 +348,7 @@ namespace GraphX.Controls
public void AddVertex(TVertex vertexData, VertexControl vertexControl)
{
if (AutoAssignMissingDataId && vertexData.ID == -1)
vertexData.ID = GetNextUniqueId();
vertexData.ID = GetNextUniqueId(true);
InternalAddVertex(vertexData, vertexControl);
if (EnableVisualPropsApply && vertexControl != null)
ReapplySingleVertexVisualProperties(vertexControl);
@ -371,7 +371,7 @@ namespace GraphX.Controls
public void AddEdge(TEdge edgeData, EdgeControl edgeControl)
{
if (AutoAssignMissingDataId && edgeData.ID == -1)
edgeData.ID = GetNextUniqueId();
edgeData.ID = GetNextUniqueId(false);
InternalAddEdge(edgeData, edgeControl);
if (EnableVisualPropsApply && edgeControl != null)
ReapplySingleEdgeVisualProperties(edgeControl);
@ -395,7 +395,7 @@ namespace GraphX.Controls
public void InsertEdge(TEdge edgeData, EdgeControl edgeControl, int num = 0)
{
if (AutoAssignMissingDataId && edgeData.ID == -1)
edgeData.ID = GetNextUniqueId();
edgeData.ID = GetNextUniqueId(false);
InternalInsertEdge(edgeData, edgeControl, num);
if (EnableVisualPropsApply && edgeControl != null)
ReapplySingleEdgeVisualProperties(edgeControl);
@ -425,17 +425,30 @@ namespace GraphX.Controls
#region Automatic data ID storage and resolving
private int _dataIdCounter = 1;
private int GetNextUniqueId()
private int _edgeDataIdCounter = 1;
private int GetNextUniqueId(bool isVertex)
{
while (_dataIdsCollection.Contains(_dataIdCounter))
if (isVertex)
{
_dataIdCounter++;
while (_dataIdsCollection.Contains(_dataIdCounter))
{
_dataIdCounter++;
}
_dataIdsCollection.Add(_dataIdCounter);
return _dataIdCounter;
}
_dataIdsCollection.Add(_dataIdCounter);
return _dataIdCounter;
while (_edgeDataIdsCollection.Contains(_edgeDataIdCounter))
{
_edgeDataIdCounter++;
}
_edgeDataIdsCollection.Add(_edgeDataIdCounter);
return _edgeDataIdCounter;
}
private readonly HashSet<int> _dataIdsCollection = new HashSet<int>();
private readonly HashSet<long> _dataIdsCollection = new HashSet<long>();
private readonly HashSet<long> _edgeDataIdsCollection = new HashSet<long>();
#endregion
@ -833,7 +846,9 @@ namespace GraphX.Controls
if (graph == null) return;
_dataIdsCollection.Clear();
_edgeDataIdsCollection.Clear();
_dataIdCounter = 1;
_edgeDataIdCounter = 1;
// First, rebuild data ID collection for all vertices and edges that already have assigned IDs.
foreach (var item in graph.Vertices.Where(a => a.ID != -1))
@ -843,15 +858,15 @@ namespace GraphX.Controls
}
foreach (var item in graph.Edges.Where(a => a.ID != -1))
{
bool added = _dataIdsCollection.Add(item.ID);
bool added = _edgeDataIdsCollection.Add(item.ID);
Debug.Assert(added, "Duplicate ID found", string.Format("Duplicate ID '{0}' found while adding an edge ID during rebuild of data ID collection.", item.ID));
}
// Generate unique IDs for all vertices and edges that don't already have a unique ID.
foreach (var item in graph.Vertices.Where(a => a.ID == -1))
item.ID = GetNextUniqueId();
item.ID = GetNextUniqueId(true);
foreach (var item in graph.Edges.Where(a => a.ID == -1))
item.ID = GetNextUniqueId();
item.ID = GetNextUniqueId(false);
}
#endregion
@ -1109,7 +1124,7 @@ namespace GraphX.Controls
/// </summary>
public void UpdateParallelEdgesData()
{
var usedIds = _edgeslist.Count > 20 ? new HashSet<int>() as ICollection<int> : new List<int>();
var usedIds = _edgeslist.Count > 20 ? new HashSet<long>() as ICollection<long> : new List<long>();
//clear IsParallel flag
EdgesList.Values.ForEach(a => a.IsParallel = false);

Просмотреть файл

@ -52,12 +52,20 @@ namespace GraphX.Controls
public void Show()
{
#if WPF
SetCurrentValue(UIElement.VisibilityProperty, Visibility.Visible);
#else
SetValue(UIElement.VisibilityProperty, Visibility.Visible);
#endif
}
public void Hide()
{
#if WPF
SetCurrentValue(UIElement.VisibilityProperty, Visibility.Collapsed);
#else
SetValue(UIElement.VisibilityProperty, Visibility.Collapsed);
#endif
}
private static VertexControl GetVertexControl(DependencyObject parent)

Просмотреть файл

@ -7,6 +7,7 @@ using System.Windows.Input;
using GraphX.PCL.Common.Enums;
using GraphX.PCL.Common.Exceptions;
using GraphX.Controls.Models;
using GraphX.PCL.Common.Interfaces;
namespace GraphX.Controls
{
@ -23,6 +24,15 @@ namespace GraphX.Controls
DefaultStyleKeyProperty.OverrideMetadata(typeof(VertexControl), new FrameworkPropertyMetadata(typeof(VertexControl)));
}
/// <summary>
/// Gets Vertex data as specified class
/// </summary>
/// <typeparam name="T">Class</typeparam>
public T GetDataVertex<T>() where T: IGraphXVertex
{
return (T)Vertex;
}
#region Position trace feature
@ -84,6 +94,15 @@ namespace GraphX.Controls
EventOptions = new VertexEventOptions(this) { PositionChangeNotification = tracePositionChange };
foreach(var item in Enum.GetValues(typeof(EventType)).Cast<EventType>())
UpdateEventhandling(item);
SizeChanged += VertexControl_SizeChanged;
}
void VertexControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
/*if (ShowLabel && VertexLabelControl != null)
VertexLabelControl.UpdatePosition();
OnPositionChanged(new Point(), GetPosition());*/
}
public override void OnApplyTemplate()

Просмотреть файл

@ -0,0 +1,98 @@

#if WPF
using System.Windows;
using DefaultEventArgs = System.EventArgs;
using System.Windows.Controls;
#elif METRO
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using DefaultEventArgs = System.Object;
#endif
using GraphX.PCL.Common.Exceptions;
namespace GraphX.Controls
{
#if METRO
[Bindable]
#endif
public class AttachableVertexLabelControl : VertexLabelControl
{
public VertexControl AttachNode { get { return (VertexControl) GetValue(AttachNodeProperty); } private set {SetValue(AttachNodeProperty, value);} }
public static readonly DependencyProperty AttachNodeProperty = DependencyProperty.Register("AttachNode", typeof(VertexControl), typeof(AttachableVertexLabelControl),
new PropertyMetadata(null));
public AttachableVertexLabelControl()
{
DataContext = this;
}
public void Attach(VertexControl node)
{
AttachNode = node;
}
protected override VertexControl GetVertexControl(DependencyObject parent)
{
if(AttachNode == null)
throw new GX_InvalidDataException("AttachableVertexLabelControl node is not attached!");
return AttachNode;
}
/* public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var container = Template.FindName("PART_container", this) as ContentPresenter;
container.Content = AttachNode.Vertex;
}*/
public override void UpdatePosition()
{
if (double.IsNaN(DesiredSize.Width) || DesiredSize.Width == 0) return;
var vc = GetVertexControl(GetParent());
if (vc == null) return;
if (LabelPositionMode == VertexLabelPositionMode.Sides)
{
var vcPos = vc.GetPosition();
Point pt;
switch (LabelPositionSide)
{
case VertexLabelPositionSide.TopRight:
pt = new Point(vcPos.X + vc.DesiredSize.Width, vcPos.Y + -DesiredSize.Height);
break;
case VertexLabelPositionSide.BottomRight:
pt = new Point(vcPos.X + vc.DesiredSize.Width, vcPos.Y + vc.DesiredSize.Height);
break;
case VertexLabelPositionSide.TopLeft:
pt = new Point(vcPos.X + -DesiredSize.Width, vcPos.Y + -DesiredSize.Height);
break;
case VertexLabelPositionSide.BottomLeft:
pt = new Point(vcPos.X + -DesiredSize.Width, vcPos.Y + vc.DesiredSize.Height);
break;
case VertexLabelPositionSide.Top:
pt = new Point(vcPos.X + vc.DesiredSize.Width * .5 - DesiredSize.Width * .5, vcPos.Y + -DesiredSize.Height);
break;
case VertexLabelPositionSide.Bottom:
pt = new Point(vcPos.X + vc.DesiredSize.Width * .5 - DesiredSize.Width * .5, vcPos.Y + vc.DesiredSize.Height);
break;
case VertexLabelPositionSide.Left:
pt = new Point(vcPos.X + -DesiredSize.Width, vcPos.Y + vc.DesiredSize.Height * .5f - DesiredSize.Height * .5);
break;
case VertexLabelPositionSide.Right:
pt = new Point(vcPos.X + vc.DesiredSize.Width, vcPos.Y + vc.DesiredSize.Height * .5f - DesiredSize.Height * .5);
break;
default:
throw new GX_InvalidDataException("UpdatePosition() -> Unknown vertex label side!");
}
LastKnownRectSize = new Rect(pt, DesiredSize);
}
else LastKnownRectSize = new Rect(LabelPosition, DesiredSize);
Arrange(LastKnownRectSize);
}
}
}

Просмотреть файл

@ -112,7 +112,7 @@ namespace GraphX.Controls
VerticalAlignment = VerticalAlignment.Top;
}
private static VertexControl GetVertexControl(DependencyObject parent)
protected virtual VertexControl GetVertexControl(DependencyObject parent)
{
while (parent != null)
{
@ -126,7 +126,7 @@ namespace GraphX.Controls
public virtual void UpdatePosition()
{
if (double.IsNaN(DesiredSize.Width) || DesiredSize.Width == 0) return;
if (double.IsNaN(DesiredSize.Width) || DesiredSize.Width == 0) return;
var vc = GetVertexControl(GetParent());
if (vc == null) return;
@ -172,12 +172,20 @@ namespace GraphX.Controls
public void Hide()
{
#if WPF
SetCurrentValue(UIElement.VisibilityProperty, Visibility.Collapsed);
#else
SetValue(UIElement.VisibilityProperty, Visibility.Collapsed);
#endif
}
public void Show()
{
#if WPF
SetCurrentValue(UIElement.VisibilityProperty, Visibility.Visible);
#else
SetValue(UIElement.VisibilityProperty, Visibility.Visible);
#endif
}
void VertexLabelControl_LayoutUpdated(object sender, DefaultEventArgs e)
@ -187,7 +195,7 @@ namespace GraphX.Controls
UpdatePosition();
}
DependencyObject GetParent()
protected virtual DependencyObject GetParent()
{
#if WPF
return VisualParent;

Просмотреть файл

@ -106,12 +106,14 @@
<Compile Include="Behaviours\DragBehaviour.cs" />
<Compile Include="Behaviours\HighlightBehaviour.cs" />
<Compile Include="Controls\EdgeControlBase.cs" />
<Compile Include="Controls\EdgeLabels\AttachableEdgeLabelControl.cs" />
<Compile Include="Controls\Misc\ControlDrawOrder.cs" />
<Compile Include="Controls\Misc\IPositionChangeNotify.cs" />
<Compile Include="Controls\Misc\IVertexConnectionPoint.cs" />
<Compile Include="Controls\VertexConnectionPoints\StaticVertexConnectionPoint.cs" />
<Compile Include="Controls\EdgePointers\DefaultEdgePointer.cs" />
<Compile Include="Controls\VertexControlBase.cs" />
<Compile Include="Controls\VertexLabels\AttachableVertexLabelControl.cs" />
<Compile Include="Controls\VertexLabels\VertexLabelControl.cs" />
<Compile Include="ExceptionExtensions.cs" />
<Compile Include="Controls\Misc\IEdgeLabelControl.cs" />

Просмотреть файл

@ -2,7 +2,7 @@ using System.Windows.Input;
namespace GraphX.Controls.Models
{
public sealed class EdgeSelectedEventArgs : System.EventArgs
public class EdgeSelectedEventArgs : System.EventArgs
{
public EdgeControl EdgeControl { get; set; }
public ModifierKeys Modifiers { get; set; }
@ -15,4 +15,16 @@ namespace GraphX.Controls.Models
MouseArgs = e;
}
}
public sealed class EdgeLabelSelectedEventArgs : EdgeSelectedEventArgs
{
public IEdgeLabelControl EdgeLabelControl { get; set; }
public EdgeLabelSelectedEventArgs(IEdgeLabelControl label, EdgeControl ec, MouseButtonEventArgs e, ModifierKeys keys)
:base(ec,e,keys)
{
EdgeLabelControl = label;
}
}
}

Просмотреть файл

@ -1,4 +1,6 @@
namespace GraphX.Controls.Models
{
public delegate void EdgeSelectedEventHandler(object sender, EdgeSelectedEventArgs args);
public delegate void EdgeLabelEventHandler(object sender, EdgeLabelSelectedEventArgs args);
}

Просмотреть файл

@ -1,6 +1,7 @@
using System;
using System.Linq;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using GraphX.Controls.Models;
using GraphX.PCL.Common.Enums;
@ -112,6 +113,19 @@ namespace GraphX.Controls
_targetWatcher = this.WatchProperty("Target", TargetChanged);
}
public event EdgeLabelEventHandler LabelMouseDown;
protected void OnLabelMouseDown(PointerRoutedEventArgs mArgs)
{
if (LabelMouseDown != null)
LabelMouseDown(this, new EdgeLabelSelectedEventArgs(EdgeLabelControl, this, mArgs));
}
protected override void OnEdgeLabelUpdated()
{
if (EdgeLabelControl is Control)
((Control)EdgeLabelControl).PointerPressed += (sender, args) => OnLabelMouseDown(args);
}
#region Position tracing
private void TargetChanged(object sender, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)

Просмотреть файл

@ -333,7 +333,7 @@ namespace GraphX.Controls
public void AddVertex(TVertex vertexData, VertexControl vertexControl)
{
if (AutoAssignMissingDataId && vertexData.ID == -1)
vertexData.ID = GetNextUniqueId();
vertexData.ID = GetNextUniqueId(true);
InternalAddVertex(vertexData, vertexControl);
if (EnableVisualPropsApply && vertexControl != null)
ReapplySingleVertexVisualProperties(vertexControl);
@ -356,7 +356,7 @@ namespace GraphX.Controls
public void AddEdge(TEdge edgeData, EdgeControl edgeControl)
{
if (AutoAssignMissingDataId && edgeData.ID == -1)
edgeData.ID = GetNextUniqueId();
edgeData.ID = GetNextUniqueId(false);
InternalAddEdge(edgeData, edgeControl);
if (EnableVisualPropsApply && edgeControl != null)
ReapplySingleEdgeVisualProperties(edgeControl);
@ -380,7 +380,7 @@ namespace GraphX.Controls
public void InsertEdge(TEdge edgeData, EdgeControl edgeControl, int num = 0)
{
if (AutoAssignMissingDataId && edgeData.ID == -1)
edgeData.ID = GetNextUniqueId();
edgeData.ID = GetNextUniqueId(false);
InternalInsertEdge(edgeData, edgeControl, num);
if (EnableVisualPropsApply && edgeControl != null)
ReapplySingleEdgeVisualProperties(edgeControl);
@ -409,18 +409,29 @@ namespace GraphX.Controls
#endregion
#region Automatic data ID storage and resolving
private int _dataIdCounter;
private int GetNextUniqueId()
private int _dataIdCounter = 1;
private int _edgeDataIdCounter = 1;
private int GetNextUniqueId(bool isVertex)
{
while (_dataIdsCollection.Contains(_dataIdCounter))
if (isVertex)
{
_dataIdCounter++;
while (_dataIdsCollection.Contains(_dataIdCounter))
{
_dataIdCounter++;
}
_dataIdsCollection.Add(_dataIdCounter);
return _dataIdCounter;
}
_dataIdsCollection.Add(_dataIdCounter);
return _dataIdCounter;
while (_edgeDataIdsCollection.Contains(_edgeDataIdCounter))
{
_edgeDataIdCounter++;
}
_edgeDataIdsCollection.Add(_edgeDataIdCounter);
return _edgeDataIdCounter;
}
private readonly HashSet<int> _dataIdsCollection = new HashSet<int>();
private readonly HashSet<long> _dataIdsCollection = new HashSet<long>();
private readonly HashSet<long> _edgeDataIdsCollection = new HashSet<long>();
#endregion
@ -495,8 +506,9 @@ namespace GraphX.Controls
{
if (VertexList.ContainsKey(item.Key))
VertexList[item.Key].SetPosition(item.Value);
if (showObjectsIfPosSpecified)
VertexList[item.Key].Visibility = Visibility.Visible;
//if (showObjectsIfPosSpecified)
// VertexList[item.Key].Visibility = Visibility.Visible;
VertexList[item.Key].SetCurrentValue(GraphAreaBase.PositioningCompleteProperty, true);
}
}
@ -529,6 +541,7 @@ namespace GraphX.Controls
var vc = ControlFactory.CreateVertexControl(it);
vc.DataContext = dataContextToDataItem ? it : null;
vc.Visibility = Visibility.Visible; // make them invisible (there is no layout positions yet calculated)
vc.SetCurrentValue(GraphAreaBase.PositioningCompleteProperty, false); // Style can make them invisible until positioning is complete (after layout positions are calculated)
InternalAddVertex(it, vc);
}
if (forceVisPropRecovery)
@ -599,7 +612,8 @@ namespace GraphX.Controls
if (MoveAnimation == null || double.IsNaN(GetX(vc)))
vc.SetPosition(item.Value.X, item.Value.Y, false);
else MoveAnimation.AddVertexData(vc, item.Value);
vc.Visibility = Visibility.Visible; //show vertexes with layout positions assigned
//vc.Visibility = Visibility.Visible; //show vertexes with layout positions assigned
vc.SetCurrentValue(GraphAreaBase.PositioningCompleteProperty, true); // Style can show vertexes with layout positions assigned
}
if (MoveAnimation != null)
{
@ -736,6 +750,8 @@ namespace GraphX.Controls
_dataIdsCollection.Clear();
_dataIdCounter = 1;
_edgeDataIdsCollection.Clear();
_edgeDataIdCounter = 1;
// First, rebuild data ID collection for all vertices and edges that already have assigned IDs.
foreach (var item in graph.Vertices.Where(a => a.ID != -1))
@ -745,15 +761,15 @@ namespace GraphX.Controls
}
foreach (var item in graph.Edges.Where(a => a.ID != -1))
{
bool added = _dataIdsCollection.Add(item.ID);
bool added = _edgeDataIdsCollection.Add(item.ID);
Debug.Assert(added, string.Format("Duplicate ID '{0}' found while adding an edge ID during rebuild of data ID collection.", item.ID));
}
// Generate unique IDs for all vertices and edges that don't already have a unique ID.
foreach (var item in graph.Vertices.Where(a => a.ID == -1))
item.ID = GetNextUniqueId();
item.ID = GetNextUniqueId(true);
foreach (var item in graph.Edges.Where(a => a.ID == -1))
item.ID = GetNextUniqueId();
item.ID = GetNextUniqueId(false);
}
#endregion
@ -1012,7 +1028,7 @@ namespace GraphX.Controls
/// </summary>
public void UpdateParallelEdgesData()
{
var usedIds = _edgeslist.Count > 20 ? new HashSet<int>() as ICollection<int> : new List<int>();
var usedIds = _edgeslist.Count > 20 ? new HashSet<long>() as ICollection<long> : new List<long>();
//clear IsParallel flag
EdgesList.Values.ForEach(a=> a.IsParallel = false);

Просмотреть файл

@ -111,7 +111,15 @@ namespace GraphX.Controls
obj.SetValue(FinalYProperty, value);
}
public static bool GetPositioningComplete(DependencyObject obj)
{
return (bool)obj.GetValue(PositioningCompleteProperty);
}
public static void SetPositioningComplete(DependencyObject obj, bool value)
{
obj.SetValue(PositioningCompleteProperty, value);
}
#endregion
#region DP - ExternalSettings
@ -185,6 +193,9 @@ namespace GraphX.Controls
public static readonly DependencyProperty MouseOverAnimationProperty =
DependencyProperty.Register("MouseOverAnimation", typeof(IBidirectionalControlAnimation), typeof(GraphAreaBase), new PropertyMetadata(null));
public static readonly DependencyProperty PositioningCompleteProperty =
DependencyProperty.RegisterAttached("PositioningComplete", typeof(bool), typeof(GraphAreaBase), new PropertyMetadata(true));
#endregion
#region Child EVENTS

Просмотреть файл

@ -161,6 +161,9 @@
<Compile Include="..\GraphX.Controls\Controls\EdgeControlBase.cs">
<Link>Controls\EdgeControlBase.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Controls\EdgeLabels\AttachableEdgeLabelControl.cs">
<Link>Controls\EdgeLabels\AttachableEdgeLabelControl.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Controls\EdgeLabels\EdgeLabelControl.cs">
<Link>Controls\EdgeLabels\EdgeLabelControl.cs</Link>
</Compile>
@ -209,6 +212,9 @@
<Compile Include="..\GraphX.Controls\Controls\VertexControlBase.cs">
<Link>Controls\VertexControlBase.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Controls\VertexLabels\AttachableVertexLabelControl.cs">
<Link>Controls\VertexLabels\AttachableVertexLabelControl.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Controls\VertexLabels\VertexLabelControl.cs">
<Link>Controls\VertexLabels\VertexLabelControl.cs</Link>
</Compile>
@ -315,18 +321,18 @@
<Content Include="Images\help_black.png" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Reference Include="QuickGraph">
<Reference Include="QuickGraph, Version=3.6.61114.0, Culture=neutral, PublicKeyToken=f3fb40175eec2af3, processorArchitecture=MSIL">
<HintPath>..\packages\QuickGraphPCL.3.6.61114.2\lib\portable-win+net4+sl5+wp8+win8+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\QuickGraph.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="QuickGraph.Graphviz">
<Reference Include="QuickGraph.Graphviz, Version=3.6.61114.0, Culture=neutral, PublicKeyToken=f3fb40175eec2af3, processorArchitecture=MSIL">
<HintPath>..\packages\QuickGraphPCL.3.6.61114.2\lib\portable-win+net4+sl5+wp8+win8+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\QuickGraph.Graphviz.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '12.0' ">
<VisualStudioVersion>12.0</VisualStudioVersion>
</PropertyGroup>

Просмотреть файл

@ -2,7 +2,7 @@ using Windows.UI.Xaml.Input;
namespace GraphX.Controls.Models
{
public sealed class EdgeSelectedEventArgs : System.EventArgs
public class EdgeSelectedEventArgs : System.EventArgs
{
public EdgeControl EdgeControl { get; set; }
public PointerRoutedEventArgs Args { get; set; }
@ -14,4 +14,16 @@ namespace GraphX.Controls.Models
Args = e;
}
}
public sealed class EdgeLabelSelectedEventArgs : EdgeSelectedEventArgs
{
public IEdgeLabelControl EdgeLabelControl { get; set; }
public EdgeLabelSelectedEventArgs(IEdgeLabelControl label, EdgeControl ec, PointerRoutedEventArgs e)
: base(ec, e)
{
EdgeLabelControl = label;
}
}
}

Просмотреть файл

@ -123,7 +123,14 @@
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="10,10,10,10"
Padding="{TemplateBinding Padding}">
Padding="{TemplateBinding Padding}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Common">
<VisualState x:Name="Snapped">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
@ -135,7 +142,13 @@
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- TODO - HIDE vertices when layout not finished yet -->
<!--<Style.Triggers>
<Trigger Property="graphxRoot:GraphAreaBase.PositioningComplete" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</Trigger>
</Style.Triggers>-->
</Style>
<!-- ENDREGION -->
<!-- REGION EDGE CONTROL -->

Просмотреть файл

@ -2,11 +2,21 @@
using System.Collections.Generic;
using Windows.Foundation;
using Windows.UI.Xaml.Media;
#if METRO
using Windows.UI.Xaml;
#endif
namespace GraphX.Controls
{
public static class TypeExtensions
{
#if METRO
public static void SetCurrentValue(this FrameworkElement el, DependencyProperty p, object value)
{
el.SetValue(p, value);
}
#endif
public static void Offset(this Point point, Point value)
{
point.X = point.X + value.X;

Просмотреть файл

@ -7,7 +7,7 @@ namespace GraphX.PCL.Common.Interfaces
/// <summary>
/// Unique object identifier
/// </summary>
int ID { get; set; }
long ID { get; set; }
/// <summary>
/// Skip object in algorithm calc and visual control generation

Просмотреть файл

@ -27,7 +27,7 @@ namespace GraphX.PCL.Common.Models
/// <summary>
/// Unique edge ID
/// </summary>
public int ID { get; set; }
public long ID { get; set; }
/// <summary>
/// Returns true if Source vertex equals Target vertex

Просмотреть файл

@ -22,7 +22,7 @@ namespace GraphX.PCL.Common.Models
/// <summary>
/// Unique vertex ID
/// </summary>
public int ID { get; set; }
public long ID { get; set; }
public bool Equals(IGraphXVertex other)
{

Просмотреть файл

@ -998,15 +998,15 @@ namespace GraphX.PCL.Logic.Algorithms.EdgeRouting
struct KeyPair
{
public KeyPair(int n1, int n2)
public KeyPair(long n1, long n2)
{
K1 = n1;
K2 = n2;
}
public readonly int K1;
public readonly long K1;
public readonly int K2;
public readonly long K2;
}
/// <summary>

Просмотреть файл

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using GraphX.PCL.Common.Interfaces;
using QuickGraph;
using QuickGraph.Algorithms.ShortestPath;
@ -40,9 +41,11 @@ namespace GraphX.PCL.Logic.Algorithms
/// <param name="g">The graph.</param>
/// <param name="set1"></param>
/// <param name="set2"></param>
/// <param name="undirected">Assume undirected graph - get both in and out edges</param>
/// <returns>Return the list of the selected edges.</returns>
public static IEnumerable<TEdge> GetEdgesBetween<TVertex, TEdge>(this IVertexAndEdgeListGraph<TVertex, TEdge> g, List<TVertex> set1, List<TVertex> set2)
public static IEnumerable<TEdge> GetEdgesBetween<TVertex, TEdge>(this IVertexAndEdgeListGraph<TVertex, TEdge> g, List<TVertex> set1, List<TVertex> set2, bool undirected = false)
where TEdge : IEdge<TVertex>
where TVertex: class
{
var edgesBetween = new List<TEdge>();
@ -50,6 +53,8 @@ namespace GraphX.PCL.Logic.Algorithms
foreach (var v in set1)
{
edgesBetween.AddRange(g.OutEdges(v).Where(edge => set2.Contains(edge.Target)));
if(undirected)
edgesBetween.AddRange(g.Edges.Where(a=> a.Target == v).Where(edge => set2.Contains(edge.Source)));
}
return edgesBetween;