+ Major code unification and refactoring pt.2

This commit is contained in:
Alexander Smirnov 2015-05-28 12:58:55 +03:00
Родитель aaaab97065
Коммит edcfeaf1a2
30 изменённых файлов: 220 добавлений и 727 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -109,3 +109,4 @@ UpgradeLog*.XML
/Nuget/*.nupkg
*.suo
*.DotSettings
*.bak

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

@ -38,6 +38,7 @@ DETAILED CHANGELOG:
+ Fixed ZoomControl zoom sometimes not firing from code call after control is loaded [WPF]
+ Fixed VB sample project dependencies and refactored code a bit
+ Fixed Fade Move animation logic to report OnCompleted event correctly [WPF]
+ Enhanced edge labels logic so now it don't require additional template bindings and modifications (Angle or RenderTransform) [WPF]
+ GraphArea::PreloadVertexes() now accepts graph param as optional (null by default) and uses LogicCore.Graph in that case [WPF, METRO]
+ Decoupled serialization logic from GraphX completely [ALL] thanks to perturbare
+ Adjusted FR and BoundedFR default values for random initial positions [All]
@ -61,6 +62,7 @@ BREAKING CHANGES:
* Now GraphX for WPF requires only .NET Framework 4.0 to build & run
* EdgeLabelControl no longer needs default Angle binding and RenderTransformOrigin setup. They are processed internally [WPF]
RELEASE 2.1.8
+ Added basic support for Image based edge pointers. Introduced new object for EdgeControl template: [WPF, METRO(bugged)]

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

@ -186,7 +186,6 @@
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
</Style>
<!--VERTEX LABEL CONTROL -->

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

@ -100,11 +100,5 @@
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="RenderTransform">
<Setter.Value>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="{Binding RelativeSource={RelativeSource AncestorType=controls:EdgeLabelControl} , Path=Angle}"/>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

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

@ -1,24 +1,34 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using GraphX.PCL.Common.Interfaces;
#if WPF
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using GraphX.PCL.Common.Interfaces;
using GraphX.PCL.Common.Models;
using System.ComponentModel;
#elif METRO
using Windows.ApplicationModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using GraphX.Measure;
using Point = Windows.Foundation.Point;
#endif
namespace GraphX.Controls
{
#if METRO
[Bindable]
#endif
public class EdgeLabelControl : ContentControl, IEdgeLabelControl
{
internal Rect LastKnownRectSize;
#region Common part
public static readonly DependencyProperty DisplayForSelfLoopedEdgesProperty = DependencyProperty.Register("DisplayForSelfLoopedEdges",
typeof(bool),
typeof(EdgeLabelControl),
new UIPropertyMetadata(false));
typeof(bool),
typeof(EdgeLabelControl),
new PropertyMetadata(false));
/// <summary>
/// Gets or sets if label should be visible for self looped edge
/// </summary>
@ -37,7 +47,23 @@ namespace GraphX.Controls
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle",
typeof(double),
typeof(EdgeLabelControl),
new UIPropertyMetadata(0.0));
new PropertyMetadata(0.0, AngleChanged));
private static void AngleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctrl = d as UIElement;
if (ctrl == null) return;
var tg = ctrl.RenderTransform as TransformGroup;
if (tg == null)
ctrl.RenderTransform = new RotateTransform {Angle = (double) e.NewValue, CenterX = .5, CenterY = .5};
else
{
var rt = (RotateTransform)tg.Children.FirstOrDefault(a => a is RotateTransform);
if (rt == null)
tg.Children.Add(new RotateTransform {Angle = (double) e.NewValue, CenterX = .5, CenterY = .5});
else rt.Angle = (double) e.NewValue;
}
}
/// <summary>
/// Gets or sets label drawing angle in degrees
/// </summary>
@ -54,7 +80,6 @@ namespace GraphX.Controls
}
private EdgeControl _edgeControl;
protected EdgeControl EdgeControl { get { return _edgeControl ?? (_edgeControl = GetEdgeControl(VisualParent)); } }
private static EdgeControl GetEdgeControl(DependencyObject parent)
{
@ -77,42 +102,14 @@ namespace GraphX.Controls
{
Visibility = Visibility.Collapsed;
}
#endregion
public EdgeLabelControl()
{
if (DesignerProperties.GetIsInDesignMode(this)) return;
LayoutUpdated += EdgeLabelControl_LayoutUpdated;
HorizontalAlignment = HorizontalAlignment.Left;
VerticalAlignment = VerticalAlignment.Top;
this.Initialized += EdgeLabelControl_Initialized;
}
void EdgeLabelControl_Initialized(object sender, EventArgs e)
{
if (EdgeControl.IsSelfLooped && !DisplayForSelfLoopedEdges) Hide();
else Show();
}
void EdgeLabelControl_LayoutUpdated(object sender, EventArgs e)
{
if (EdgeControl == null || !EdgeControl.ShowLabel) return;
if (LastKnownRectSize == Rect.Empty || double.IsNaN(LastKnownRectSize.Width) || LastKnownRectSize.Width == 0)
{
UpdateLayout();
UpdatePosition();
}
else Arrange(LastKnownRectSize);
}
private static double GetLabelDistance(double edgeLength)
{
return edgeLength / 2; // set the label halfway the length of the edge
return edgeLength * .5; // set the label halfway the length of the edge
}
/// <summary>
/// Automaticaly update edge label position
/// </summary>
@ -130,12 +127,11 @@ namespace GraphX.Controls
//if hidden
if (Visibility != Visibility.Visible) return;
if(EdgeControl.IsSelfLooped)
if (EdgeControl.IsSelfLooped)
{
var idesiredSize = DesiredSize;
var pt = EdgeControl.Source.GetCenterPosition();
pt.Offset(-idesiredSize.Width / 2, (EdgeControl.Source.DesiredSize.Height * .5) + 2 + (idesiredSize.Height * .5));
LastKnownRectSize = new Rect(pt.X, pt.Y, idesiredSize.Width, idesiredSize.Height);
SetSelfLoopedSize(pt, idesiredSize);
Arrange(LastKnownRectSize);
return;
}
@ -145,9 +141,9 @@ namespace GraphX.Controls
double edgeLength = 0;
var routingInfo = EdgeControl.Edge as IRoutingInfo;
if (routingInfo != null)
if (routingInfo != null)
{
var routePoints = routingInfo.RoutingPoints == null ? null : routingInfo.RoutingPoints.ToWindows();
var routePoints = routingInfo.RoutingPoints == null ? null : routingInfo.RoutingPoints.ToWindows();
if (routePoints == null || routePoints.Length == 0)
{
@ -156,7 +152,6 @@ namespace GraphX.Controls
}
else
{
// the edge has one or more segments
// compute the total length of all the segments
edgeLength = 0;
@ -190,7 +185,6 @@ namespace GraphX.Controls
p2 = newp2;
}
}
// The label control should be laid out on a rectangle, in the middle of the edge
var angleBetweenPoints = MathHelper.GetAngleBetweenPoints(p1, p2);
var desiredSize = DesiredSize;
@ -216,11 +210,26 @@ namespace GraphX.Controls
Angle += 180; // Reorient the label so that it's always "pointing north"
}
LastKnownRectSize = new Rect(centerPoint.X - desiredSize.Width / 2, centerPoint.Y - desiredSize.Height / 2, desiredSize.Width, desiredSize.Height);
UpdateFinalPosition(centerPoint, desiredSize);
Arrange(LastKnownRectSize);
}
#if WPF
internal Rect LastKnownRectSize;
protected EdgeControl EdgeControl { get { return _edgeControl ?? (_edgeControl = GetEdgeControl(VisualParent)); } }
private void SetSelfLoopedSize(Point pt, Size idesiredSize)
{
pt.Offset(-idesiredSize.Width / 2, (EdgeControl.Source.DesiredSize.Height * .5) + 2 + (idesiredSize.Height * .5));
LastKnownRectSize = new Rect(pt.X, pt.Y, idesiredSize.Width, idesiredSize.Height);
}
private void UpdateFinalPosition(Point centerPoint, Size desiredSize)
{
LastKnownRectSize = new Rect(centerPoint.X - desiredSize.Width / 2, centerPoint.Y - desiredSize.Height / 2, desiredSize.Width, desiredSize.Height);
}
/// <summary>
/// Get label rectangular size
/// </summary>
@ -237,6 +246,93 @@ namespace GraphX.Controls
Arrange(LastKnownRectSize);
}
public EdgeLabelControl()
{
if (DesignerProperties.GetIsInDesignMode(this)) return;
RenderTransformOrigin = new Point(.5,.5);
LayoutUpdated += EdgeLabelControl_LayoutUpdated;
HorizontalAlignment = HorizontalAlignment.Left;
VerticalAlignment = VerticalAlignment.Top;
Initialized += EdgeLabelControl_Loaded;
}
void EdgeLabelControl_Loaded(object sender, EventArgs e)
{
if (EdgeControl.IsSelfLooped && !DisplayForSelfLoopedEdges) Hide();
else Show();
}
void EdgeLabelControl_LayoutUpdated(object sender, EventArgs e)
{
if (EdgeControl == null || !EdgeControl.ShowLabel) return;
if (LastKnownRectSize == Rect.Empty || double.IsNaN(LastKnownRectSize.Width) || LastKnownRectSize.Width == 0)
{
UpdateLayout();
UpdatePosition();
}
else Arrange(LastKnownRectSize);
}
#elif METRO
internal Windows.Foundation.Rect LastKnownRectSize;
protected EdgeControl EdgeControl { get { return _edgeControl ?? (_edgeControl = GetEdgeControl(Parent)); } }
private void SetSelfLoopedSize(Point pt, Windows.Foundation.Size idesiredSize)
{
pt = pt.Offset(-idesiredSize.Width / 2, (EdgeControl.Source.DesiredSize.Height * .5) + 2 + (idesiredSize.Height * .5));
LastKnownRectSize = new Windows.Foundation.Rect(pt.X, pt.Y, idesiredSize.Width, idesiredSize.Height);
}
private void UpdateFinalPosition(Point centerPoint, Windows.Foundation.Size desiredSize)
{
if (double.IsNaN(centerPoint.X)) centerPoint.X = 0;
if (double.IsNaN(centerPoint.Y)) centerPoint.Y = 0;
LastKnownRectSize = new Windows.Foundation.Rect(centerPoint.X - desiredSize.Width / 2, centerPoint.Y - desiredSize.Height / 2, desiredSize.Width, desiredSize.Height);
}
/// <summary>
/// Get label rectangular size
/// </summary>
public Rect GetSize()
{
return LastKnownRectSize.ToGraphX();
}
/// <summary>
/// Set label rectangular size
/// </summary>
public void SetSize(Windows.Foundation.Rect size)
{
LastKnownRectSize = size;
}
public EdgeLabelControl()
{
DefaultStyleKey = typeof(EdgeLabelControl);
if (DesignMode.DesignModeEnabled) return;
LayoutUpdated += EdgeLabelControl_LayoutUpdated;
HorizontalAlignment = HorizontalAlignment.Left;
VerticalAlignment = VerticalAlignment.Top;
Loaded += EdgeLabelControl_Loaded;
}
void EdgeLabelControl_Loaded(object sender, RoutedEventArgs e)
{
if (EdgeControl.IsSelfLooped && !DisplayForSelfLoopedEdges) Hide();
else Show();
}
void EdgeLabelControl_LayoutUpdated(object sender, object e)
{
if (EdgeControl == null || !EdgeControl.ShowLabel) return;
if (LastKnownRectSize == Windows.Foundation.Rect.Empty || double.IsNaN(LastKnownRectSize.Width) || LastKnownRectSize.Width == 0)
{
UpdateLayout();
UpdatePosition();
}
else Arrange(LastKnownRectSize);
}
#endif
public void Dispose()
{
_edgeControl = null;

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

@ -140,8 +140,8 @@
<Compile Include="Controls\Misc\IEdgePointer.cs" />
<Compile Include="Controls\Misc\IGraphArea.cs" />
<Compile Include="Controls\Misc\IGraphControl.cs" />
<Compile Include="Models\Interfaces\IGraphControlFactory.cs" />
<Compile Include="Animations\Interfaces\IOneWayControlAnimation.cs" />
<Compile Include="Models\Interfaces\IGraphControlFactory.cs" />
<Compile Include="Models\PropertyChangeNotifier.cs" />
<Compile Include="Models\RemoveControlEventHandler.cs" />
<Compile Include="Models\StateStorage.cs" />

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

@ -1,4 +1,8 @@
#if WPF
using System.Windows;
#elif METRO
using Windows.Foundation;
#endif
namespace GraphX.Controls.Models
{

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

@ -1,4 +1,8 @@
using System.Windows;
#if WPF
using System.Windows;
#elif METRO
using Windows.UI.Xaml;
#endif
namespace GraphX.Controls.Models
{

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

@ -1,4 +1,8 @@
using System.Windows;
# if WPF
using System.Windows;
#elif METRO
using Windows.UI.Xaml;
#endif
namespace GraphX.Controls.Models
{

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

@ -2,11 +2,15 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using GraphX.PCL.Common.Exceptions;
using GraphX.PCL.Common.Interfaces;
using GraphX.PCL.Common.Models;
using QuickGraph;
#if WPF
using System.Windows;
#elif METRO
using Windows.UI.Xaml;
#endif
namespace GraphX.Controls.Models
{

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

@ -45,6 +45,7 @@ namespace GraphX.Controls.Models
} }
private bool _mousedblclick = true;
#if WPF
/// <summary>
/// Gets or sets if position trace enabled. If enabled then PositionChanged event will be rised on each X or Y property change.
/// True by default.
@ -63,6 +64,7 @@ namespace GraphX.Controls.Models
}
}
private bool _poschange = true;
#endif
private VertexControl _vc;

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

@ -1,5 +1,9 @@
using System;
#if WPF
using System.Windows;
#elif METRO
using Windows.Foundation;
#endif
namespace GraphX.Controls.Models
{

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

@ -526,13 +526,6 @@
</Setter>
<Setter Property="DisplayForSelfLoopedEdges" Value="False"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
<Setter Property="RenderTransform">
<Setter.Value>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="{Binding RelativeSource={RelativeSource AncestorType=local1:EdgeLabelControl} , Path=Angle}"/>
</Setter.Value>
</Setter>
</Style>
<!-- ENDREGION -->

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

@ -1,260 +0,0 @@
using System;
using System.Diagnostics;
using System.Linq;
using Windows.ApplicationModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
using GraphX.Measure;
using GraphX.PCL.Common.Interfaces;
using Point = Windows.Foundation.Point;
namespace GraphX.Controls
{
[Bindable]
public class EdgeLabelControl : ContentControl, IEdgeLabelControl
{
public static readonly DependencyProperty DisplayForSelfLoopedEdgesProperty = DependencyProperty.Register("DisplayForSelfLoopedEdges",
typeof(bool),
typeof(EdgeLabelControl),
new PropertyMetadata(false));
/// <summary>
/// Gets or sets if label should be visible for self looped edge
/// </summary>
public bool DisplayForSelfLoopedEdges
{
get
{
return (bool)GetValue(DisplayForSelfLoopedEdgesProperty);
}
set
{
SetValue(DisplayForSelfLoopedEdgesProperty, value);
}
}
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register("Angle",
typeof(double),
typeof(EdgeLabelControl),
new PropertyMetadata(0.0, AngleChanged));
private static void AngleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctrl = d as UIElement;
if (ctrl == null)
{
Debug.WriteLine("VertexLabelControl -> dp isn't uielement!");
return;
}
var tg = ctrl.RenderTransform as TransformGroup;
if (tg == null) ctrl.RenderTransform = new RotateTransform { Angle = (double)e.NewValue, CenterX = .5, CenterY = .5 };
else
{
var rt = tg.Children.FirstOrDefault(a => a is RotateTransform);
if (rt == null)
tg.Children.Add(new RotateTransform { Angle = (double)e.NewValue, CenterX = .5, CenterY = .5 });
else (rt as RotateTransform).Angle = (double)e.NewValue;
}
}
private EdgeControl _edgeControl;
protected EdgeControl EdgeControl { get { return _edgeControl ?? (_edgeControl = GetEdgeControl(Parent)); } }
/// <summary>
/// Gets or sets label drawing angle in degrees
/// </summary>
public double Angle
{
get
{
return (double)GetValue(AngleProperty);
}
set
{
SetValue(AngleProperty, value);
}
}
public void Show()
{
if (EdgeControl.IsSelfLooped && !DisplayForSelfLoopedEdges) return;
Visibility = Visibility.Visible;
}
public void Hide()
{
Visibility = Visibility.Collapsed;
}
public Rect GetSize()
{
return LastKnownRectSize.ToGraphX();
}
public void SetSize(Windows.Foundation.Rect size)
{
LastKnownRectSize = size;
}
public EdgeLabelControl()
{
DefaultStyleKey = typeof(EdgeLabelControl);
if (DesignMode.DesignModeEnabled) return;
LayoutUpdated += EdgeLabelControl_LayoutUpdated;
HorizontalAlignment = HorizontalAlignment.Left;
VerticalAlignment = VerticalAlignment.Top;
Loaded += EdgeLabelControl_Loaded;
}
void EdgeLabelControl_Loaded(object sender, RoutedEventArgs e)
{
if (EdgeControl.IsSelfLooped && !DisplayForSelfLoopedEdges) Hide();
else Show();
}
void EdgeLabelControl_LayoutUpdated(object sender, object e)
{
if (EdgeControl == null || !EdgeControl.ShowLabel) return;
if (LastKnownRectSize == Windows.Foundation.Rect.Empty || double.IsNaN(LastKnownRectSize.Width) || LastKnownRectSize.Width == 0)
{
UpdateLayout();
UpdatePosition();
}
else Arrange(LastKnownRectSize);
}
private static EdgeControl GetEdgeControl(DependencyObject parent)
{
while (parent != null)
{
var control = parent as EdgeControl;
if (control != null) return control;
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
private static double GetLabelDistance(double edgeLength)
{
return edgeLength *.5; // set the label halfway the length of the edge
}
public void UpdatePosition()
{
if (double.IsNaN(DesiredSize.Width) || DesiredSize.Width == 0) return;
// if (!IsLoaded)
// return;
if (EdgeControl == null)
return;
if (EdgeControl.Source == null || EdgeControl.Target == null)
{
Debug.WriteLine("EdgeLabelControl_LayoutUpdated() -> Got empty edgecontrol!");
return;
}
//if hidden
if (Visibility != Visibility.Visible) return;
if (EdgeControl.IsSelfLooped)
{
var idesiredSize = DesiredSize;
var pt = EdgeControl.Source.GetCenterPosition();
pt = pt.Offset(-idesiredSize.Width / 2, (EdgeControl.Source.DesiredSize.Height * .5) + 2 + (idesiredSize.Height * .5));
LastKnownRectSize = new Windows.Foundation.Rect(pt.X, pt.Y, idesiredSize.Width, idesiredSize.Height);
Arrange(LastKnownRectSize);
return;
}
var p1 = EdgeControl.SourceConnectionPoint.GetValueOrDefault();
var p2 = EdgeControl.TargetConnectionPoint.GetValueOrDefault();
double edgeLength = 0;
var routingInfo = EdgeControl.Edge as IRoutingInfo;
if (routingInfo != null)
{
var routePoints = routingInfo.RoutingPoints == null ? null : routingInfo.RoutingPoints.ToWindows();
if (routePoints == null || routePoints.Length == 0)
{
// the edge is a single segment (p1,p2)
edgeLength = GetLabelDistance(MathHelper.GetDistanceBetweenPoints(p1, p2));
}
else
{
// the edge has one or more segments
// compute the total length of all the segments
edgeLength = 0;
var rplen = routePoints.Length;
for (var i = 0; i <= rplen; ++i)
if (i == 0)
edgeLength += MathHelper.GetDistanceBetweenPoints(p1, routePoints[0]);
else if (i == rplen)
edgeLength += MathHelper.GetDistanceBetweenPoints(routePoints[rplen - 1], p2);
else
edgeLength += MathHelper.GetDistanceBetweenPoints(routePoints[i - 1], routePoints[i]);
// find the line segment where the half distance is located
edgeLength = GetLabelDistance(edgeLength);
var newp1 = p1;
var newp2 = p2;
for (var i = 0; i <= rplen; ++i)
{
double lengthOfSegment;
if (i == 0)
lengthOfSegment = MathHelper.GetDistanceBetweenPoints(newp1 = p1, newp2 = routePoints[0]);
else if (i == rplen)
lengthOfSegment = MathHelper.GetDistanceBetweenPoints(newp1 = routePoints[rplen - 1], newp2 = p2);
else
lengthOfSegment = MathHelper.GetDistanceBetweenPoints(newp1 = routePoints[i - 1], newp2 = routePoints[i]);
if (lengthOfSegment >= edgeLength)
break;
edgeLength -= lengthOfSegment;
}
// redefine our edge points
p1 = newp1;
p2 = newp2;
}
}
// The label control should be laid out on a rectangle, in the middle of the edge
var angleBetweenPoints = MathHelper.GetAngleBetweenPoints(p1, p2);
var desiredSize = DesiredSize;
bool flipAxis = p1.X > p2.X; // Flip axis if source is "after" target
// Calculate the center point of the edge
var centerPoint = new Point(p1.X + edgeLength * Math.Cos(angleBetweenPoints), p1.Y - edgeLength * Math.Sin(angleBetweenPoints));
if (EdgeControl.AlignLabelsToEdges)
{
// If we're aligning labels to the edges make sure add the label vertical offset
var yEdgeOffset = EdgeControl.LabelVerticalOffset;
if (flipAxis) // If we've flipped axis, move the offset to the other side of the edge
yEdgeOffset = -yEdgeOffset;
// Adjust offset for rotation. Remember, the offset is perpendicular from the edge tangent.
// Slap on 90 degrees to the angle between the points, to get the direction of the offset.
centerPoint.Y -= yEdgeOffset * Math.Sin(angleBetweenPoints + Math.PI / 2);
centerPoint.X += yEdgeOffset * Math.Cos(angleBetweenPoints + Math.PI / 2);
// Angle is in degrees
Angle = -angleBetweenPoints * 180 / Math.PI;
if (flipAxis)
Angle += 180; // Reorient the label so that it's always "pointing north"
}
if (double.IsNaN(centerPoint.X)) centerPoint.X = 0;
if (double.IsNaN(centerPoint.Y)) centerPoint.Y = 0;
LastKnownRectSize = new Windows.Foundation.Rect(centerPoint.X - desiredSize.Width / 2, centerPoint.Y - desiredSize.Height / 2, desiredSize.Width, desiredSize.Height);
Arrange(LastKnownRectSize);
}
internal Windows.Foundation.Rect LastKnownRectSize;
public void Dispose()
{
_edgeControl = null;
}
}
}

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

@ -189,13 +189,13 @@ namespace GraphX.Controls
public GraphArea()
{
ControlFactory = new GraphControlFactory { FactoryRootArea = this };
ControlFactory = new GraphControlFactory(this);
StateStorage = new StateStorage<TVertex, TEdge, TGraph>(this);
EnableVisualPropsRecovery = true;
EnableVisualPropsApply = true;
//CacheMode = new BitmapCache(2) { EnableClearType = false, SnapsToDevicePixels = true };
Transitions = new TransitionCollection();
Transitions.Add(new ContentThemeTransition());
Transitions = new TransitionCollection {new ContentThemeTransition()};
#region Designer Data
if (DesignMode.DesignModeEnabled)
{

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

@ -34,7 +34,7 @@
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE;NETFX_CORE</DefineConstants>
<DefineConstants>TRACE;NETFX_CORE, METRO</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
@ -158,6 +158,9 @@
<Compile Include="..\GraphX.Controls\Behaviours\HighlightBehaviour.cs">
<Link>Behaviours\HighlightBehaviour.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Controls\EdgeLabels\EdgeLabelControl.cs">
<Link>Controls\EdgeLabels\EdgeLabelControl.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\CustomHelper.cs">
<Link>CustomHelper.cs</Link>
</Compile>
@ -167,8 +170,46 @@
<Compile Include="..\GraphX.Controls\MathHelper.cs">
<Link>MathHelper.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\AnimationFactory.cs">
<Link>Models\AnimationFactory.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\ContentSizeChangedEventArgs.cs">
<Link>Models\ContentSizeChangedEventArgs.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\ControlEventArgs.cs">
<Link>Models\ControlEventArgs.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\EdgeEventOptions.cs">
<Link>Models\EdgeEventOptions.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\EdgeSelectedEventHandler.cs">
<Link>Models\EdgeSelectedEventHandler.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\GraphControlFactory.cs">
<Link>Models\GraphControlFactory.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\Interfaces\IGraphControlFactory.cs">
<Link>Models\Interfaces\IGraphControlFactory.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\RemoveControlEventHandler.cs">
<Link>Models\RemoveControlEventHandler.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\StateStorage.cs">
<Link>Models\StateStorage.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\VertexEventOptions.cs">
<Link>Models\VertexEventOptions.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\VertexPositionChangedEH.cs">
<Link>Models\VertexPositionChangedEH.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\VertexPositionEventArgs.cs">
<Link>Models\VertexPositionEventArgs.cs</Link>
</Compile>
<Compile Include="..\GraphX.Controls\Models\VertexSelectedEventHandler.cs">
<Link>Models\VertexSelectedEventHandler.cs</Link>
</Compile>
<Compile Include="Controls\EdgeControl.cs" />
<Compile Include="Controls\EdgeLabels\EdgeLabelControl.cs" />
<Compile Include="Controls\EdgePointers\EdgePointerImage.cs" />
<Compile Include="Controls\EdgePointers\EdgePointerPath.cs" />
<Compile Include="Controls\GraphArea.cs" />
@ -204,30 +245,17 @@
<Compile Include="DpExtensions.cs" />
<Compile Include="Controls\Misc\EdgeDashStyle.cs" />
<Compile Include="Controls\Misc\LogicCoreChangedAction.cs" />
<Compile Include="Models\AnimationFactory.cs" />
<Compile Include="Models\AnimationHelper.cs" />
<Compile Include="Models\ContentSizeChangedEventArgs.cs" />
<Compile Include="Models\ControlEventArgs.cs" />
<Compile Include="Models\DelegateCommand.cs" />
<Compile Include="Models\DispatcherHelper.cs" />
<Compile Include="Models\EdgeEventOptions.cs" />
<Compile Include="Models\EdgeSelectedEventArgs.cs" />
<Compile Include="Models\EdgeSelectedEventHandler.cs" />
<Compile Include="Models\FileServiceProviderMETRO.cs" />
<Compile Include="Models\GraphControlFactory.cs" />
<Compile Include="Controls\Misc\IGraphArea.cs" />
<Compile Include="Controls\Misc\IGraphControl.cs" />
<Compile Include="Models\Interfaces\IGraphControlFactory.cs" />
<Compile Include="Models\ModifierKeys.cs" />
<Compile Include="Models\MouseButtonEventArgs.cs" />
<Compile Include="Models\RemoveControlEventHandler.cs" />
<Compile Include="Models\StateStorage.cs" />
<Compile Include="Models\VertexEventOptions.cs" />
<Compile Include="Models\VertexMovedEventArgs.cs" />
<Compile Include="Models\VertexPositionChangedEH.cs" />
<Compile Include="Models\VertexPositionEventArgs.cs" />
<Compile Include="Models\VertexSelectedEventArgs.cs" />
<Compile Include="Models\VertexSelectedEventHandler.cs" />
<Compile Include="Models\XamlTypes\ViewModelBase.cs" />
<Compile Include="Models\XamlTypes\ViewModelXamlMember.cs" />
<Compile Include="Models\XamlTypes\ViewModelXamlMetadataProvider.cs" />

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

@ -1,55 +0,0 @@
using System;
using GraphX.Controls.Animations;
namespace GraphX.Controls.Models
{
public static class AnimationFactory
{
/// <summary>
/// Create move animation by supplied type
/// </summary>
/// <param name="type">Animation type</param>
/// <param name="duration">Animation duration</param>
public static MoveAnimationBase CreateMoveAnimation(MoveAnimation type, TimeSpan duration)
{
switch (type)
{
case MoveAnimation.None:
return null;
case MoveAnimation.Move:
return new MoveSimpleAnimation(duration);
case MoveAnimation.Fade:
return new MoveFadeAnimation(duration);
}
return null;
}
public static IOneWayControlAnimation CreateDeleteAnimation(DeleteAnimation type, double duration = .3)
{
switch (type)
{
case DeleteAnimation.None:
return null;
case DeleteAnimation.Shrink:
return new DeleteShrinkAnimation(duration);
case DeleteAnimation.Fade:
return new DeleteFadeAnimation(duration);
}
return null;
}
public static IBidirectionalControlAnimation CreateMouseOverAnimation(MouseOverAnimation type, double duration = .3)
{
switch (type)
{
case MouseOverAnimation.None:
return null;
case MouseOverAnimation.Scale:
return new MouseOverScaleAnimation(duration);
}
return null;
}
}
}

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

@ -1,17 +0,0 @@
using Windows.Foundation;
namespace GraphX.Controls.Models
{
public sealed class ContentSizeChangedEventArgs : System.EventArgs
{
public Rect OldSize { get; private set; }
public Rect NewSize { get; private set; }
public ContentSizeChangedEventArgs(Rect oldSize, Rect newSize)
: base()
{
OldSize = oldSize;
NewSize = newSize;
}
}
}

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

@ -1,46 +0,0 @@
using GraphX.PCL.Common.Enums;
namespace GraphX.Controls.Models
{
public sealed class EdgeEventOptions
{
/// <summary>
/// Gets or sets if MouseMove event should be enabled
/// </summary>
public bool MouseMoveEnabled { get { return mousemove; } set { if (mousemove != value) { mousemove = value; _ec.UpdateEventhandling(EventType.MouseMove); } } }
private bool mousemove = true;
/// <summary>
/// Gets or sets if MouseEnter event should be enabled
/// </summary>
public bool MouseEnterEnabled { get { return mouseenter; } set { if (mouseenter != value) { mouseenter = value; _ec.UpdateEventhandling(EventType.MouseEnter); } } }
private bool mouseenter = true;
/// <summary>
/// Gets or sets if MouseLeave event should be enabled
/// </summary>
public bool MouseLeaveEnabled { get { return mouseleave; } set { if (mouseleave != value) { mouseleave = value; _ec.UpdateEventhandling(EventType.MouseLeave); } } }
private bool mouseleave = true;
/// <summary>
/// Gets or sets if MouseDown event should be enabled
/// </summary>
public bool MouseClickEnabled { get { return mouseclick; } set { if (mouseclick != value) { mouseclick = value; _ec.UpdateEventhandling(EventType.MouseClick); } } }
private bool mouseclick = true;
/// <summary>
/// Gets or sets if MouseDoubleClick event should be enabled
/// </summary>
public bool MouseDoubleClickEnabled { get { return mousedblclick; } set { if (mousedblclick != value) { mousedblclick = value; _ec.UpdateEventhandling(EventType.MouseDoubleClick); } } }
private bool mousedblclick = true;
private EdgeControl _ec;
public EdgeEventOptions(EdgeControl ec)
{
_ec = ec;
}
public void Clean()
{
_ec = null;
}
}
}

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

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

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

@ -1,24 +0,0 @@
using Windows.UI.Xaml;
namespace GraphX.Controls.Models
{
public class GraphControlFactory : IGraphControlFactory
{
public EdgeControl CreateEdgeControl(VertexControl source, VertexControl target, object edge, bool showLabels = false, bool showArrows = true, Visibility visibility = Visibility.Visible)
{
var edgectrl = new EdgeControl(source, target, edge, showLabels, showArrows) { Visibility = visibility, RootArea = FactoryRootArea};
return edgectrl;
}
public VertexControl CreateVertexControl(object vertexData)
{
return new VertexControl(vertexData) {RootArea = FactoryRootArea};
}
public GraphAreaBase FactoryRootArea { get; set; }
}
}

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

@ -1,13 +0,0 @@
using Windows.UI.Xaml;
namespace GraphX.Controls.Models
{
public interface IGraphControlFactory
{
EdgeControl CreateEdgeControl(VertexControl source, VertexControl target, object edge, bool showLabels = false, bool showArrows = true, Visibility visibility = Visibility.Visible);
VertexControl CreateVertexControl(object vertexData);
GraphAreaBase FactoryRootArea { set; get; }
}
}

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

@ -1,4 +0,0 @@
namespace GraphX.Controls.Models
{
public delegate void RemoveControlEventHandler(object sender, ControlEventArgs args);
}

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

@ -1,131 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.UI.Xaml;
using GraphX.PCL.Common.Exceptions;
using GraphX.PCL.Common.Interfaces;
using GraphX.PCL.Common.Models;
using QuickGraph;
namespace GraphX.Controls.Models
{
public class StateStorage<TVertex, TEdge, TGraph>: IDisposable
where TEdge : class, IGraphXEdge<TVertex>
where TVertex: class, IGraphXVertex
where TGraph: class, IMutableBidirectionalGraph<TVertex, TEdge>
{
private Dictionary<string, GraphState<TVertex, TEdge, TGraph>> _states;
private GraphArea<TVertex, TEdge, TGraph> _area;
public StateStorage(GraphArea<TVertex, TEdge, TGraph> area)
{
_area = area;
_states = new Dictionary<string, GraphState<TVertex, TEdge, TGraph>>();
}
/// <summary>
/// Returns true if state with supplied ID exists in the current states collection
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool ContainsState(string id)
{
return _states.ContainsKey(id);
}
/// <summary>
/// Save current graph state into memory, including visual and data controls
/// </summary>
/// <param name="id">New unique state id</param>
/// <param name="description">Optional state description</param>
public void SaveState(string id, string description = "")
{
if (_area.LogicCore == null)
throw new GX_InvalidDataException("LogicCore -> Not initialized!");
var vposlist = new Dictionary<TVertex, Measure.Point>();
foreach (var item in _area.VertexList)
vposlist.Add(item.Key, item.Value.GetPositionGraphX());
var vedgelist = new List<TEdge>();
foreach (var item in _area.EdgesList)
if (item.Value.Visibility == Visibility.Visible)
vedgelist.Add(item.Key);
var state = new GraphState<TVertex, TEdge, TGraph>(id, _area.LogicCore.Graph, vposlist, vedgelist, description);
_states.Add(id, state);
}
/// <summary>
/// Load previously saved state into layout
/// </summary>
/// <param name="id">Unique state id</param>
public void LoadState(string id)
{
if (_area.LogicCore == null)
throw new GX_InvalidDataException("GraphArea.LogicCore -> Not initialized!");
if (!_states.ContainsKey(id))
{
Debug.WriteLine(string.Format("LoadState() -> State id {0} not found! Skipping...", id));
return;
}
// _area.RemoveAllVertices();
// _area.RemoveAllEdges();
//One action: clear all, preload vertices, assign Graph property
_area.PreloadVertexes(_states[id].Graph, true, true);
_area.LogicCore.Graph = _states[id].Graph;
//setup vertex positions
foreach (var item in _states[id].VertexPositions)
{
_area.VertexList[item.Key].SetPosition(item.Value.X, item.Value.Y, true);
_area.VertexList[item.Key].Visibility = Visibility.Visible;
}
//setup visible edges
foreach (var item in _states[id].VisibleEdges)
{
var edgectrl = _area.ControlFactory.CreateEdgeControl(_area.VertexList[item.Source], _area.VertexList[item.Target],
item);
_area.InsertEdge(item, edgectrl);
//edgectrl.UpdateEdge();
}
_area.UpdateLayout();
foreach (var item in _area.EdgesList.Values)
{
item.UpdateEdge();
}
}
/// <summary>
/// Remove state by id
/// </summary>
/// <param name="id">Unique state id</param>
public void RemoveState(string id)
{
if (_states.ContainsKey(id))
_states.Remove(id);
}
/// <summary>
/// Get all states from the storage
/// </summary>
public Dictionary<string, GraphState<TVertex, TEdge, TGraph>> GetStates()
{
return _states;
}
/// <summary>
/// Get all states from the storage
/// </summary>
/// <param name="id">Unique state id</param>
public GraphState<TVertex, TEdge, TGraph> GetState(string id)
{
return ContainsState(id) ? _states[id] : null;
}
public void Dispose()
{
_area = null;
}
}
}

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

@ -1,46 +0,0 @@
using GraphX.PCL.Common.Enums;
namespace GraphX.Controls.Models
{
public sealed class VertexEventOptions
{
/// <summary>
/// Gets or sets if MouseMove event should be enabled
/// </summary>
public bool MouseMoveEnabled { get { return _mousemove; } set { if (_mousemove != value) { _mousemove = value; _vc.UpdateEventhandling(EventType.MouseMove); } } }
private bool _mousemove = true;
/// <summary>
/// Gets or sets if MouseEnter event should be enabled
/// </summary>
public bool MouseEnterEnabled { get { return _mouseenter; } set { if (_mouseenter != value) { _mouseenter = value; _vc.UpdateEventhandling(EventType.MouseEnter); } } }
private bool _mouseenter = true;
/// <summary>
/// Gets or sets if MouseLeave event should be enabled
/// </summary>
public bool MouseLeaveEnabled { get { return _mouseleave; } set { if (_mouseleave != value) { _mouseleave = value; _vc.UpdateEventhandling(EventType.MouseLeave); } } }
private bool _mouseleave = true;
/// <summary>
/// Gets or sets if MouseDown event should be enabled
/// </summary>
public bool MouseClickEnabled { get { return _mouseclick; } set { if (_mouseclick != value) { _mouseclick = value; _vc.UpdateEventhandling(EventType.MouseClick); } } }
private bool _mouseclick = true;
/// <summary>
/// Gets or sets if MouseDoubleClick event should be enabled
/// </summary>
public bool MouseDoubleClickEnabled { get { return _mousedblclick; } set { if (_mousedblclick != value) { _mousedblclick = value; _vc.UpdateEventhandling(EventType.MouseDoubleClick); } } }
private bool _mousedblclick = true;
private VertexControl _vc;
public VertexEventOptions(VertexControl vc)
{
_vc = vc;
}
public void Clean()
{
_vc = null;
}
}
}

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

@ -8,7 +8,6 @@ namespace GraphX.Controls.Models
public PointerRoutedEventArgs Args { get; private set; }
public VertexMovedEventArgs(VertexControl vc, PointerRoutedEventArgs e)
: base()
{
Args = e;
VertexControl = vc;

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

@ -1,4 +0,0 @@
namespace GraphX.Controls.Models
{
public delegate void VertexPositionChangedEH(object sender, VertexPositionEventArgs args);
}

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

@ -1,28 +0,0 @@
using System;
using Windows.Foundation;
namespace GraphX.Controls.Models
{
public sealed class VertexPositionEventArgs : EventArgs
{
/// <summary>
/// Vertex control
/// </summary>
public VertexControl VertexControl { get; private set; }
/// <summary>
/// Attached coordinates X and Y
/// </summary>
public Point Position { get; private set; }
/// <summary>
/// Offset of the vertex control within the GraphArea
/// </summary>
public Point OffsetPosition { get; private set; }
public VertexPositionEventArgs(Point offset, Point pos, VertexControl vc)
{
OffsetPosition = offset;
VertexControl = vc;
Position = pos;
}
}
}

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

@ -8,7 +8,6 @@ namespace GraphX.Controls.Models
public PointerRoutedEventArgs Args { get; private set; }
public VertexSelectedEventArgs(VertexControl vc, PointerRoutedEventArgs e)
: base()
{
VertexControl = vc;
Args = e;

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

@ -1,8 +0,0 @@
namespace GraphX.Controls.Models
{
public delegate void VertexSelectedEventHandler(object sender, VertexSelectedEventArgs args);
public delegate void VertexMovedEventHandler(object sender, VertexMovedEventArgs e);
public delegate void ContentSizeChangedEventHandler(object sender, ContentSizeChangedEventArgs e);
}