mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-16 22:26:36 +08:00
整理一下项目文件
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Images\file.png" />
|
||||
<None Remove="Images\FormatPainter.cur" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.31" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="WpfAnimatedGif" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="$(DefineConstants.Contains(NETCOREAPP)) == true">
|
||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\file.png" />
|
||||
<Resource Include="Images\FormatPainter.cur" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Images\Gifs\car_chase.gif">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
256
AIStudio.Wpf.DiagramDesigner/Adorners/RubberbandAdorner.cs
Normal file
256
AIStudio.Wpf.DiagramDesigner/Adorners/RubberbandAdorner.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class RubberbandAdorner : Adorner
|
||||
{
|
||||
private Point? startPoint;
|
||||
private Point? endPoint;
|
||||
private List<Point> pointList = new List<Point>();
|
||||
private List<PointDesignerItemViewModel> pointDesignerItemViewModelList = new List<PointDesignerItemViewModel>();
|
||||
private Pen rubberbandPen;
|
||||
|
||||
private DesignerCanvas _designerCanvas;
|
||||
|
||||
private IDiagramViewModel _viewModel { get { return _designerCanvas.DataContext as IDiagramViewModel; } }
|
||||
private IDiagramServiceProvider _service { get { return DiagramServicesProvider.Instance.Provider; } }
|
||||
|
||||
public RubberbandAdorner(DesignerCanvas designerCanvas, Point? dragStartPoint)
|
||||
: base(designerCanvas)
|
||||
{
|
||||
this._designerCanvas = designerCanvas;
|
||||
this.startPoint = dragStartPoint;
|
||||
rubberbandPen = new Pen(Brushes.LightSlateGray, 1);
|
||||
rubberbandPen.DashStyle = new DashStyle(new double[] { 2 }, 1);
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
if (!this.IsMouseCaptured)
|
||||
this.CaptureMouse();
|
||||
|
||||
endPoint = e.GetPosition(this);
|
||||
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polyline)
|
||||
{
|
||||
if (pointList.Count == 0 && this.startPoint.HasValue)
|
||||
{
|
||||
pointList.Add(this.startPoint.Value);
|
||||
}
|
||||
pointList.Add(endPoint.Value);
|
||||
}
|
||||
|
||||
UpdateSelection();
|
||||
this.InvalidateVisual();
|
||||
}
|
||||
else if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
|
||||
{
|
||||
if (pointList.Count == 0 && this.startPoint.HasValue)
|
||||
{
|
||||
pointList.Add(this.startPoint.Value);
|
||||
var item = new PointDesignerItemViewModel(startPoint.Value);
|
||||
item.ShowConnectors = true;
|
||||
_viewModel.DirectAddItemCommand.Execute(item);
|
||||
pointDesignerItemViewModelList.Add(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.IsMouseCaptured) this.ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine && e.ChangedButton == MouseButton.Left )
|
||||
{
|
||||
endPoint = e.GetPosition(this);
|
||||
|
||||
bool isend = false;
|
||||
var connector = ControlExtession.TryFindFromPoint<PointConnector>(this._designerCanvas, endPoint.Value);
|
||||
if (connector != null)
|
||||
{
|
||||
if (object.Equals(connector.DataContext, pointDesignerItemViewModelList[0].TopConnector))
|
||||
{
|
||||
isend = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isend == false)
|
||||
{
|
||||
pointList.Add(endPoint.Value);
|
||||
var item = new PointDesignerItemViewModel(endPoint.Value);
|
||||
item.ShowConnectors = true;
|
||||
_viewModel.DirectAddItemCommand.Execute(item);
|
||||
pointDesignerItemViewModelList.Add(item);
|
||||
|
||||
UpdateSelection();
|
||||
this.InvalidateVisual();
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
this._service.DrawModeViewModel.SetDrawMode(DrawMode.Polygon);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// release mouse capture
|
||||
if (this.IsMouseCaptured) this.ReleaseMouseCapture();
|
||||
|
||||
// remove this adorner from adorner layer
|
||||
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this._designerCanvas);
|
||||
if (adornerLayer != null)
|
||||
adornerLayer.Remove(this);
|
||||
|
||||
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Line ||
|
||||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Rectangle ||
|
||||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Ellipse ||
|
||||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polyline ||
|
||||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polygon ||
|
||||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine ||
|
||||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
|
||||
{
|
||||
if (this.startPoint.HasValue && this.endPoint.HasValue)
|
||||
{
|
||||
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polyline
|
||||
|| this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polygon
|
||||
|| this._service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
|
||||
{
|
||||
ShapeDesignerItemViewModel itemBase = new ShapeDesignerItemViewModel(this._service.DrawModeViewModel.GetDrawMode(), pointList);
|
||||
_viewModel.AddItemCommand.Execute(itemBase);
|
||||
itemBase.PointDesignerItemViewModels.ForEach(p =>
|
||||
{
|
||||
p.ParentId = itemBase.Id;
|
||||
_viewModel.DirectAddItemCommand.Execute(p);
|
||||
});
|
||||
}
|
||||
else if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
|
||||
{
|
||||
TextDesignerItemViewModel itemBase = new TextDesignerItemViewModel();
|
||||
Point position = e.GetPosition(this);
|
||||
itemBase.Left = Math.Min(this.startPoint.Value.X, this.endPoint.Value.X);
|
||||
itemBase.Top = Math.Min(this.startPoint.Value.Y, this.endPoint.Value.Y);
|
||||
itemBase.ItemWidth = Math.Abs(this.endPoint.Value.X - this.startPoint.Value.X);
|
||||
itemBase.ItemHeight = Math.Abs(this.endPoint.Value.Y - this.startPoint.Value.Y);
|
||||
|
||||
_viewModel.AddItemCommand.Execute(itemBase);
|
||||
}
|
||||
else
|
||||
{
|
||||
ShapeDesignerItemViewModel itemBase = new ShapeDesignerItemViewModel(this._service.DrawModeViewModel.GetDrawMode(), new List<Point> { this.startPoint.Value, this.endPoint.Value });
|
||||
_viewModel.AddItemCommand.Execute(itemBase);
|
||||
itemBase.PointDesignerItemViewModels.ForEach(p =>
|
||||
{
|
||||
p.ParentId = itemBase.Id;
|
||||
_viewModel.DirectAddItemCommand.Execute(p);
|
||||
});
|
||||
}
|
||||
}
|
||||
this._service.DrawModeViewModel.ResetDrawMode();
|
||||
}
|
||||
|
||||
pointDesignerItemViewModelList.ForEach(p => _viewModel.DirectRemoveItemCommand.Execute(p));
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
{
|
||||
base.OnRender(dc);
|
||||
|
||||
// without a background the OnMouseMove event would not be fired !
|
||||
// Alternative: implement a Canvas as a child of this adorner, like
|
||||
// the ConnectionAdorner does.
|
||||
dc.DrawRectangle(Brushes.Transparent, null, new Rect(RenderSize));
|
||||
|
||||
if (this.startPoint.HasValue && this.endPoint.HasValue)
|
||||
{
|
||||
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Line)
|
||||
{
|
||||
dc.DrawLine(rubberbandPen, this.startPoint.Value, this.endPoint.Value);
|
||||
}
|
||||
else if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Ellipse)
|
||||
{
|
||||
var centerPoint = new Point((this.startPoint.Value.X + this.endPoint.Value.X) / 2, (this.startPoint.Value.Y + this.endPoint.Value.Y) / 2);
|
||||
dc.DrawEllipse(Brushes.Transparent, rubberbandPen, centerPoint, Math.Abs(this.startPoint.Value.X - this.endPoint.Value.X) / 2, Math.Abs(this.startPoint.Value.Y - this.endPoint.Value.Y) / 2);
|
||||
}
|
||||
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.Polyline)
|
||||
{
|
||||
var disList = pointList.ToList();
|
||||
for (int i = 1; i < pointList.Count; i++)
|
||||
{
|
||||
dc.DrawLine(rubberbandPen, disList[i - 1], disList[i]);
|
||||
}
|
||||
}
|
||||
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
|
||||
{
|
||||
var disList = pointList.ToList();
|
||||
for (int i = 1; i < pointList.Count; i++)
|
||||
{
|
||||
dc.DrawLine(rubberbandPen, disList[i - 1], disList[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dc.DrawRectangle(Brushes.Transparent, rubberbandPen, new Rect(this.startPoint.Value, this.endPoint.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private T GetParent<T>(Type parentType, DependencyObject dependencyObject) where T : DependencyObject
|
||||
{
|
||||
DependencyObject parent = VisualTreeHelper.GetParent(dependencyObject);
|
||||
if (parent.GetType() == parentType)
|
||||
return (T)parent;
|
||||
|
||||
return GetParent<T>(parentType, parent);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void UpdateSelection()
|
||||
{
|
||||
IDiagramViewModel vm = (_designerCanvas.DataContext as IDiagramViewModel);
|
||||
Rect rubberBand = new Rect(startPoint.Value, endPoint.Value);
|
||||
ItemsControl itemsControl = GetParent<ItemsControl>(typeof(ItemsControl), _designerCanvas);
|
||||
|
||||
foreach (SelectableDesignerItemViewModelBase item in vm.Items)
|
||||
{
|
||||
if (item is SelectableDesignerItemViewModelBase)
|
||||
{
|
||||
DependencyObject container = itemsControl.ItemContainerGenerator.ContainerFromItem(item);
|
||||
|
||||
Rect itemRect = VisualTreeHelper.GetDescendantBounds((Visual)container);
|
||||
Rect itemBounds = ((Visual)container).TransformToAncestor(_designerCanvas).TransformBounds(itemRect);
|
||||
|
||||
if (rubberBand.Contains(itemBounds))
|
||||
{
|
||||
//item.IsSelected = true;
|
||||
vm.SelectionService.AddToSelection(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
|
||||
{
|
||||
//item.IsSelected = false;
|
||||
vm.SelectionService.RemoveFromSelection(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Input;
|
||||
using AIStudio.Wpf.DiagramDesigner.Helpers;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public static class DragAndDropProps
|
||||
{
|
||||
#region EnabledForDrag
|
||||
|
||||
public static readonly DependencyProperty EnabledForDragProperty =
|
||||
DependencyProperty.RegisterAttached("EnabledForDrag", typeof(bool), typeof(DragAndDropProps),
|
||||
new FrameworkPropertyMetadata((bool)false,
|
||||
new PropertyChangedCallback(OnEnabledForDragChanged)));
|
||||
|
||||
public static bool GetEnabledForDrag(DependencyObject d)
|
||||
{
|
||||
return (bool)d.GetValue(EnabledForDragProperty);
|
||||
}
|
||||
|
||||
public static void SetEnabledForDrag(DependencyObject d, bool value)
|
||||
{
|
||||
d.SetValue(EnabledForDragProperty, value);
|
||||
}
|
||||
|
||||
private static void OnEnabledForDragChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
FrameworkElement fe = (FrameworkElement) d;
|
||||
|
||||
|
||||
if((bool)e.NewValue)
|
||||
{
|
||||
fe.PreviewMouseDown += Fe_PreviewMouseDown;
|
||||
fe.MouseMove += Fe_MouseMove;
|
||||
}
|
||||
else
|
||||
{
|
||||
fe.PreviewMouseDown -= Fe_PreviewMouseDown;
|
||||
fe.MouseMove -= Fe_MouseMove;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DragStartPoint
|
||||
|
||||
public static readonly DependencyProperty DragStartPointProperty =
|
||||
DependencyProperty.RegisterAttached("DragStartPoint", typeof(Point?), typeof(DragAndDropProps));
|
||||
|
||||
public static Point? GetDragStartPoint(DependencyObject d)
|
||||
{
|
||||
return (Point?)d.GetValue(DragStartPointProperty);
|
||||
}
|
||||
|
||||
|
||||
public static void SetDragStartPoint(DependencyObject d, Point? value)
|
||||
{
|
||||
d.SetValue(DragStartPointProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
static void Fe_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
|
||||
{
|
||||
Point? dragStartPoint = GetDragStartPoint((DependencyObject)sender);
|
||||
|
||||
if (e.LeftButton != MouseButtonState.Pressed)
|
||||
dragStartPoint = null;
|
||||
|
||||
if (dragStartPoint.HasValue)
|
||||
{
|
||||
DragObject dataObject = new DragObject();
|
||||
dataObject.ContentType = (((FrameworkElement)sender).DataContext as ToolBoxData).Type;
|
||||
dataObject.DesiredSize = new Size(65, 65);
|
||||
dataObject.Icon = (((FrameworkElement)sender).DataContext as ToolBoxData).Icon;
|
||||
dataObject.ColorViewModel = (((FrameworkElement)sender).DataContext as ToolBoxData).ColorViewModel;
|
||||
dataObject.DesignerItem = (((FrameworkElement)sender).DataContext as ToolBoxData).Addition as DesignerItemBase;
|
||||
|
||||
DragDrop.DoDragDrop((DependencyObject)sender, dataObject, DragDropEffects.Copy);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void Fe_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
SetDragStartPoint((DependencyObject)sender, e.GetPosition((IInputElement)sender));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public static class ItemConnectProps
|
||||
{
|
||||
#region EnabledForConnection
|
||||
|
||||
public static readonly DependencyProperty EnabledForConnectionProperty =
|
||||
DependencyProperty.RegisterAttached("EnabledForConnection", typeof(bool), typeof(ItemConnectProps),
|
||||
new FrameworkPropertyMetadata((bool)false,
|
||||
new PropertyChangedCallback(OnEnabledForConnectionChanged)));
|
||||
|
||||
public static bool GetEnabledForConnection(DependencyObject d)
|
||||
{
|
||||
return (bool)d.GetValue(EnabledForConnectionProperty);
|
||||
}
|
||||
|
||||
public static void SetEnabledForConnection(DependencyObject d, bool value)
|
||||
{
|
||||
d.SetValue(EnabledForConnectionProperty, value);
|
||||
}
|
||||
|
||||
private static void OnEnabledForConnectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
FrameworkElement fe = (FrameworkElement)d;
|
||||
|
||||
|
||||
if ((bool)e.NewValue)
|
||||
{
|
||||
fe.MouseEnter += Fe_MouseEnter;
|
||||
}
|
||||
else
|
||||
{
|
||||
fe.MouseEnter -= Fe_MouseEnter;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
static void Fe_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (((FrameworkElement)sender).DataContext is DesignerItemViewModelBase)
|
||||
{
|
||||
DesignerItemViewModelBase designerItem = (DesignerItemViewModelBase)((FrameworkElement)sender).DataContext;
|
||||
designerItem.ShowConnectors = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public static class SelectionProps
|
||||
{
|
||||
#region EnabledForSelection
|
||||
|
||||
public static readonly DependencyProperty EnabledForSelectionProperty =
|
||||
DependencyProperty.RegisterAttached("EnabledForSelection", typeof(bool), typeof(SelectionProps),
|
||||
new FrameworkPropertyMetadata((bool)false,
|
||||
new PropertyChangedCallback(OnEnabledForSelectionChanged)));
|
||||
|
||||
public static bool GetEnabledForSelection(DependencyObject d)
|
||||
{
|
||||
return (bool)d.GetValue(EnabledForSelectionProperty);
|
||||
}
|
||||
|
||||
public static void SetEnabledForSelection(DependencyObject d, bool value)
|
||||
{
|
||||
d.SetValue(EnabledForSelectionProperty, value);
|
||||
}
|
||||
|
||||
private static void OnEnabledForSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
FrameworkElement fe = (FrameworkElement)d;
|
||||
if ((bool)e.NewValue)
|
||||
{
|
||||
fe.PreviewMouseDown += Fe_PreviewMouseDown;
|
||||
}
|
||||
else
|
||||
{
|
||||
fe.PreviewMouseDown -= Fe_PreviewMouseDown;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
static void Fe_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
SelectableDesignerItemViewModelBase selectableDesignerItemViewModelBase =
|
||||
(SelectableDesignerItemViewModelBase)((FrameworkElement)sender).DataContext;
|
||||
|
||||
if(selectableDesignerItemViewModelBase != null && selectableDesignerItemViewModelBase.IsHitTestVisible)
|
||||
{
|
||||
if ((Keyboard.Modifiers & (ModifierKeys.Shift | ModifierKeys.Control)) != ModifierKeys.None)
|
||||
{
|
||||
if ((Keyboard.Modifiers & (ModifierKeys.Shift)) != ModifierKeys.None)
|
||||
{
|
||||
selectableDesignerItemViewModelBase.IsSelected = !selectableDesignerItemViewModelBase.IsSelected;
|
||||
}
|
||||
|
||||
if ((Keyboard.Modifiers & (ModifierKeys.Control)) != ModifierKeys.None)
|
||||
{
|
||||
selectableDesignerItemViewModelBase.IsSelected = !selectableDesignerItemViewModelBase.IsSelected;
|
||||
}
|
||||
}
|
||||
else if (!selectableDesignerItemViewModelBase.IsSelected)
|
||||
{
|
||||
foreach (SelectableDesignerItemViewModelBase item in selectableDesignerItemViewModelBase.Parent.SelectedItems)
|
||||
item.IsSelected = false;
|
||||
|
||||
selectableDesignerItemViewModelBase.Parent.SelectedItems.Clear();
|
||||
//selectableDesignerItemViewModelBase.IsSelected = true;
|
||||
selectableDesignerItemViewModelBase.Parent.SelectionService.AddToSelection(selectableDesignerItemViewModelBase);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
AIStudio.Wpf.DiagramDesigner/Attributes/CanDoAttribute.cs
Normal file
11
AIStudio.Wpf.DiagramDesigner/Attributes/CanDoAttribute.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class CanDoAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
152
AIStudio.Wpf.DiagramDesigner/Controls/BorderResizeThumb.cs
Normal file
152
AIStudio.Wpf.DiagramDesigner/Controls/BorderResizeThumb.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Controls
|
||||
{
|
||||
public class BorderResizeThumb : Thumb
|
||||
{
|
||||
#region ResizeMode
|
||||
|
||||
/// <summary>
|
||||
/// BindingWidthAndHeight Dependency Property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ResizeModeProperty =
|
||||
DependencyProperty.Register("ResizeMode", typeof(ResizeMode), typeof(BorderResizeThumb),
|
||||
new FrameworkPropertyMetadata(ResizeMode.Size));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the BindingWidthAndHeight property. This dependency property
|
||||
/// indicates if the ResizableItemsControl is in Composing mode.
|
||||
/// </summary>
|
||||
public ResizeMode ResizeMode
|
||||
{
|
||||
get { return (ResizeMode)GetValue(ResizeModeProperty); }
|
||||
set { SetValue(ResizeModeProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ResizeElement
|
||||
|
||||
/// <summary>
|
||||
/// BindingWidthAndHeight Dependency Property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ResizeElementProperty =
|
||||
DependencyProperty.Register("ResizeElement", typeof(FrameworkElement), typeof(BorderResizeThumb),
|
||||
new FrameworkPropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the BindingWidthAndHeight property. This dependency property
|
||||
/// indicates if the ResizableItemsControl is in Composing mode.
|
||||
/// </summary>
|
||||
public FrameworkElement ResizeElement
|
||||
{
|
||||
get { return (FrameworkElement)GetValue(ResizeElementProperty); }
|
||||
set { SetValue(ResizeElementProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
public BorderResizeThumb()
|
||||
{
|
||||
base.DragDelta += new DragDeltaEventHandler(ResizeThumb_DragDelta);
|
||||
}
|
||||
|
||||
void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
if (ResizeElement == null) return;
|
||||
|
||||
if (ResizeMode == ResizeMode.Size)
|
||||
{
|
||||
switch (base.VerticalAlignment)
|
||||
{
|
||||
case VerticalAlignment.Top:
|
||||
if (ResizeElement.Height - e.VerticalChange > ResizeElement.MinHeight && ResizeElement.Height - e.VerticalChange < ResizeElement.MaxHeight)
|
||||
{
|
||||
ResizeElement.Height -= e.VerticalChange;
|
||||
}
|
||||
break;
|
||||
case VerticalAlignment.Bottom:
|
||||
if (ResizeElement.Height + e.VerticalChange > ResizeElement.MinHeight && ResizeElement.Height + e.VerticalChange < ResizeElement.MaxHeight)
|
||||
{
|
||||
ResizeElement.Height += e.VerticalChange;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (base.HorizontalAlignment)
|
||||
{
|
||||
case HorizontalAlignment.Left:
|
||||
if (ResizeElement.Width - e.HorizontalChange > ResizeElement.MinWidth && ResizeElement.Width - e.HorizontalChange < ResizeElement.MaxWidth)
|
||||
{
|
||||
ResizeElement.Width -= e.HorizontalChange;
|
||||
}
|
||||
break;
|
||||
case HorizontalAlignment.Right:
|
||||
if (ResizeElement.Width + e.HorizontalChange > ResizeElement.MinWidth && ResizeElement.Width + e.HorizontalChange < ResizeElement.MaxWidth)
|
||||
{
|
||||
ResizeElement.Width += e.HorizontalChange;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ResizeMode == ResizeMode.Margin)
|
||||
{
|
||||
switch (base.VerticalAlignment)
|
||||
{
|
||||
case VerticalAlignment.Top:
|
||||
if (ResizeElement.Margin.Top + e.VerticalChange > 0)
|
||||
{
|
||||
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left, ResizeElement.Margin.Top + e.VerticalChange, ResizeElement.Margin.Right, ResizeElement.Margin.Bottom);
|
||||
}
|
||||
break;
|
||||
case VerticalAlignment.Bottom:
|
||||
if (ResizeElement.Margin.Bottom - e.VerticalChange > 0)
|
||||
{
|
||||
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left, ResizeElement.Margin.Top, ResizeElement.Margin.Right, ResizeElement.Margin.Bottom - e.VerticalChange);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (base.HorizontalAlignment)
|
||||
{
|
||||
case HorizontalAlignment.Left:
|
||||
if (ResizeElement.Margin.Left + e.HorizontalChange > 0)
|
||||
{
|
||||
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left + e.HorizontalChange, ResizeElement.Margin.Top, ResizeElement.Margin.Right, ResizeElement.Margin.Bottom);
|
||||
}
|
||||
break;
|
||||
case HorizontalAlignment.Right:
|
||||
if (ResizeElement.Margin.Right - e.HorizontalChange > 0)
|
||||
{
|
||||
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left, ResizeElement.Margin.Top, ResizeElement.Margin.Right - e.HorizontalChange, ResizeElement.Margin.Bottom);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ResizeMode == ResizeMode.DragMargin)
|
||||
{
|
||||
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left + e.HorizontalChange, ResizeElement.Margin.Top + e.VerticalChange, ResizeElement.Margin.Right - e.HorizontalChange, ResizeElement.Margin.Bottom - e.VerticalChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ResizeMode
|
||||
{
|
||||
Size,
|
||||
Margin,
|
||||
DragMargin,
|
||||
}
|
||||
}
|
||||
84
AIStudio.Wpf.DiagramDesigner/Controls/CinchMenuItem.cs
Normal file
84
AIStudio.Wpf.DiagramDesigner/Controls/CinchMenuItem.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a mechanism for constructing MenuItems
|
||||
/// within a ViewModel
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <![CDATA[
|
||||
///
|
||||
/// AND IN VIEWMODEL C# DO THIS TO CREATE MENUS
|
||||
/// private List<CinchMenuItem> CreateMenus()
|
||||
/// {
|
||||
/// var menu = new List<CinchMenuItem>();
|
||||
/// //create the File Menu
|
||||
/// var miFile = new CinchMenuItem("File");
|
||||
/// var miExit = new CinchMenuItem("Exit");
|
||||
/// miExit.Command = ExitApplicationCommand;
|
||||
/// miFile.Children.Add(miExit);
|
||||
/// menu.Add(miFile);
|
||||
/// //create the Actions Menu
|
||||
/// menu.Add(new CinchMenuItem("Actions"));
|
||||
/// return menu;
|
||||
/// }
|
||||
///
|
||||
///
|
||||
/// public List<CinchMenuItem> MenuOptions
|
||||
/// {
|
||||
/// get
|
||||
/// {
|
||||
/// return CreateMenus();
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// AND IN XAML DO THE FOLLOWING FOR THE STYLE
|
||||
/// <Style x:Key="ContextMenuItemStyle">
|
||||
/// <Setter Property="MenuItem.Header" Value="{Binding Text}"/>
|
||||
/// <Setter Property="MenuItem.ItemsSource" Value="{Binding Children}"/>
|
||||
/// <Setter Property="MenuItem.Command" Value="{Binding Command}" />
|
||||
/// <Setter Property="MenuItem.Icon" Value="{Binding Icon}" />
|
||||
/// </Style>
|
||||
///
|
||||
/// AND YOU CAN CREATE A MENU LIKE THIS
|
||||
/// <StackPanel Orientation="Horizontal">
|
||||
/// <Image Source="{Binding Image}" Width="16" Height="16" />
|
||||
/// <TextBlock Margin="5" HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
/// Text="{Binding Header}" />
|
||||
/// <StackPanel.ContextMenu>
|
||||
/// <ContextMenu ItemContainerStyle="{StaticResource ContextMenuItemStyle}"
|
||||
/// ItemsSource="{Binding MenuOptions}" />
|
||||
/// </StackPanel.ContextMenu>
|
||||
/// </StackPanel>
|
||||
/// ]]>
|
||||
/// </example>
|
||||
public class CinchMenuItem
|
||||
{
|
||||
#region Public Properties
|
||||
public String Text { get; set; }
|
||||
public String IconUrl { get; set; }
|
||||
public bool IsChecked { get; set; }
|
||||
public bool IsCheckable { get; set; }
|
||||
public List<CinchMenuItem> Children { get; private set; }
|
||||
public Object CommandParameter { get; set; }
|
||||
public SimpleCommand Command { get; set; }
|
||||
#endregion
|
||||
|
||||
#region Ctor
|
||||
public CinchMenuItem()
|
||||
{
|
||||
Children = new List<CinchMenuItem>();
|
||||
}
|
||||
|
||||
public CinchMenuItem(string item)
|
||||
{
|
||||
Text = item;
|
||||
Children = new List<CinchMenuItem>();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
40
AIStudio.Wpf.DiagramDesigner/Controls/Connector.cs
Normal file
40
AIStudio.Wpf.DiagramDesigner/Controls/Connector.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class Connector : Control
|
||||
{
|
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonDown(e);
|
||||
DesignerCanvas canvas = GetDesignerCanvas(this);
|
||||
if (canvas != null)
|
||||
{
|
||||
canvas.SourceConnector = this;
|
||||
}
|
||||
}
|
||||
|
||||
public ConnectorOrientation Orientation { get; set; }
|
||||
|
||||
// iterate through visual tree to get parent DesignerCanvas
|
||||
private DesignerCanvas GetDesignerCanvas(DependencyObject element)
|
||||
{
|
||||
while (element != null && !(element is DesignerCanvas))
|
||||
element = VisualTreeHelper.GetParent(element);
|
||||
|
||||
return element as DesignerCanvas;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
516
AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs
Normal file
516
AIStudio.Wpf.DiagramDesigner/Controls/DesignerCanvas.cs
Normal file
@@ -0,0 +1,516 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Media;
|
||||
using System.Xml;
|
||||
using System.Linq;
|
||||
using System.Windows.Shapes;
|
||||
using System.Windows.Resources;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class DesignerCanvas : Canvas
|
||||
{
|
||||
private IDiagramViewModel _viewModel { get { return DataContext as IDiagramViewModel; } }
|
||||
private IDiagramServiceProvider _service { get { return DiagramServicesProvider.Instance.Provider; } }
|
||||
|
||||
private ConnectorViewModel partialConnection;
|
||||
private List<Connector> connectorsHit = new List<Connector>();
|
||||
|
||||
private Point? rubberbandSelectionStartPoint = null;
|
||||
|
||||
#region GridCellSize
|
||||
|
||||
public static readonly DependencyProperty GridCellSizeProperty =
|
||||
DependencyProperty.Register("GridCellSize",
|
||||
typeof(Size),
|
||||
typeof(DesignerCanvas),
|
||||
new FrameworkPropertyMetadata(new Size(50, 50), FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Size GridCellSize
|
||||
{
|
||||
get { return (Size)GetValue(GridCellSizeProperty); }
|
||||
set { SetValue(GridCellSizeProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ShowGrid
|
||||
|
||||
public static readonly DependencyProperty ShowGridProperty =
|
||||
DependencyProperty.Register("ShowGrid",
|
||||
typeof(bool),
|
||||
typeof(DesignerCanvas),
|
||||
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public bool ShowGrid
|
||||
{
|
||||
get { return (bool)GetValue(ShowGridProperty); }
|
||||
set { SetValue(ShowGridProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GridColor
|
||||
|
||||
public static readonly DependencyProperty GridColorProperty =
|
||||
DependencyProperty.Register("GridColor",
|
||||
typeof(Color),
|
||||
typeof(DesignerCanvas),
|
||||
new FrameworkPropertyMetadata(Colors.LightGray, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public Color GridColor
|
||||
{
|
||||
get { return (Color)GetValue(GridColorProperty); }
|
||||
set { SetValue(GridColorProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GridMargin 单位mm
|
||||
|
||||
public static readonly DependencyProperty GridMarginProperty =
|
||||
DependencyProperty.Register("GridMargin",
|
||||
typeof(double),
|
||||
typeof(DesignerCanvas),
|
||||
new FrameworkPropertyMetadata(28d, FrameworkPropertyMetadataOptions.AffectsRender));
|
||||
|
||||
public double GridMargin
|
||||
{
|
||||
get { return (double)GetValue(GridMarginProperty); }
|
||||
set { SetValue(GridMarginProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public DesignerCanvas()
|
||||
{
|
||||
this.AllowDrop = true;
|
||||
Mediator.Instance.Register(this);
|
||||
|
||||
_service.PropertyChanged += _service_PropertyChanged;
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
{
|
||||
var rect = new Rect(0, 0, RenderSize.Width, RenderSize.Height);
|
||||
dc.DrawRectangle(Background, null, rect);
|
||||
if (ShowGrid && GridCellSize.Width > 0 && GridCellSize.Height > 0)
|
||||
DrawGrid(dc, rect);
|
||||
}
|
||||
|
||||
protected virtual void DrawGrid(DrawingContext dc, Rect rect)
|
||||
{
|
||||
//using .5 forces wpf to draw a single pixel line
|
||||
for (var i = GridMargin + 0.5; i < rect.Height - GridMargin; i += GridCellSize.Height)
|
||||
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(GridMargin, i), new Point(rect.Width - GridMargin, i));
|
||||
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(GridMargin, rect.Height - GridMargin), new Point(rect.Width - GridMargin, rect.Height - GridMargin));
|
||||
|
||||
for (var i = GridMargin + 0.5; i < rect.Width - GridMargin; i += GridCellSize.Width)
|
||||
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(i, GridMargin), new Point(i, rect.Height - GridMargin));
|
||||
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(rect.Width - GridMargin, GridMargin), new Point(rect.Width - GridMargin, rect.Height - GridMargin));
|
||||
}
|
||||
|
||||
private void _service_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (sender is IDrawModeViewModel)
|
||||
{
|
||||
if (e.PropertyName == nameof(CursorMode))
|
||||
{
|
||||
if (_service.DrawModeViewModel.CursorMode == CursorMode.Format)
|
||||
{
|
||||
EnterFormat();
|
||||
}
|
||||
else if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
|
||||
{
|
||||
EnterMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Format/Move
|
||||
private void EnterFormat()
|
||||
{
|
||||
StreamResourceInfo sri = Application.GetResourceStream(new Uri("pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Images/FormatPainter.cur", UriKind.RelativeOrAbsolute));
|
||||
this.Cursor = new Cursor(sri.Stream);
|
||||
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
|
||||
{
|
||||
item.IsHitTestVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnterMove()
|
||||
{
|
||||
this.Cursor = Cursors.SizeAll;
|
||||
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
|
||||
{
|
||||
item.IsHitTestVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ExitCursor()
|
||||
{
|
||||
this.Cursor = Cursors.Arrow;
|
||||
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
|
||||
{
|
||||
item.IsHitTestVisible = true;
|
||||
}
|
||||
_service.DrawModeViewModel.CursorMode = CursorMode.Normal;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void Format(SelectableDesignerItemViewModelBase source, SelectableDesignerItemViewModelBase target)
|
||||
{
|
||||
CopyHelper.CopyPropertyValue(source.ColorViewModel, target.ColorViewModel);
|
||||
CopyHelper.CopyPropertyValue(source.FontViewModel, target.FontViewModel);
|
||||
}
|
||||
|
||||
private Connector sourceConnector;
|
||||
public Connector SourceConnector
|
||||
{
|
||||
get { return sourceConnector; }
|
||||
set
|
||||
{
|
||||
if (sourceConnector != value)
|
||||
{
|
||||
sourceConnector = value;
|
||||
connectorsHit.Add(sourceConnector);
|
||||
FullyCreatedConnectorInfo sourceDataItem = sourceConnector.DataContext as FullyCreatedConnectorInfo;
|
||||
|
||||
|
||||
Rect rectangleBounds = sourceConnector.TransformToVisual(this).TransformBounds(new Rect(sourceConnector.RenderSize));
|
||||
Point point = new Point(rectangleBounds.Left + (rectangleBounds.Width / 2),
|
||||
rectangleBounds.Bottom + (rectangleBounds.Height / 2));
|
||||
partialConnection = new ConnectorViewModel(sourceDataItem, new PartCreatedConnectionInfo(point), _service.DrawModeViewModel.VectorLineDrawMode);
|
||||
_viewModel.DirectAddItemCommand.Execute(partialConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FullyCreatedConnectorInfo sourceConnectorInfo;
|
||||
public FullyCreatedConnectorInfo SourceConnectorInfo
|
||||
{
|
||||
get { return sourceConnectorInfo; }
|
||||
set
|
||||
{
|
||||
if (sourceConnectorInfo != value)
|
||||
{
|
||||
sourceConnectorInfo = value;
|
||||
sourceConnector = new Connector() { Name = "占位" };//占位使用
|
||||
connectorsHit.Add(sourceConnector);
|
||||
|
||||
Rect rectangleBounds = new Rect(sourceConnectorInfo.DataItem.Left, sourceConnectorInfo.DataItem.Top, 3, 3);
|
||||
Point point = new Point(rectangleBounds.Left + (rectangleBounds.Width / 2),
|
||||
rectangleBounds.Bottom + (rectangleBounds.Height / 2));
|
||||
partialConnection = new ConnectorViewModel(sourceConnectorInfo, new PartCreatedConnectionInfo(point), _service.DrawModeViewModel.VectorLineDrawMode);
|
||||
_viewModel.DirectAddItemCommand.Execute(partialConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseDown(e);
|
||||
|
||||
if (_service.DrawModeViewModel.CursorMode == CursorMode.Format)
|
||||
{
|
||||
var element = (e.OriginalSource as FrameworkElement);
|
||||
if (element.DataContext is SelectableDesignerItemViewModelBase target)
|
||||
{
|
||||
Format(_viewModel.SelectedItems.FirstOrDefault(), target);
|
||||
return;
|
||||
}
|
||||
|
||||
ExitCursor();
|
||||
}
|
||||
else if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
|
||||
{
|
||||
ExitCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
//if we are source of event, we are rubberband selecting
|
||||
if (e.Source == this)
|
||||
{
|
||||
// in case that this click is the start for a
|
||||
// drag operation we cache the start point
|
||||
rubberbandSelectionStartPoint = e.GetPosition(this);
|
||||
|
||||
IDiagramViewModel vm = (this.DataContext as IDiagramViewModel);
|
||||
if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
|
||||
{
|
||||
vm.ClearSelectedItemsCommand.Execute(null);
|
||||
|
||||
}
|
||||
e.Handled = true;
|
||||
|
||||
if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.ConnectingLine)
|
||||
{
|
||||
if (connectorsHit.Count == 0)
|
||||
{
|
||||
LinkPointDesignerItemViewModel pointItemView = new LinkPointDesignerItemViewModel(rubberbandSelectionStartPoint.Value);
|
||||
_viewModel.DirectAddItemCommand.Execute(pointItemView);
|
||||
SourceConnectorInfo = pointItemView.TopConnector;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
Point currentPoint = e.GetPosition(this);
|
||||
_viewModel.CurrentPoint = currentPoint;
|
||||
var point = CursorPointManager.GetCursorPosition();
|
||||
_viewModel.CurrentColor = ColorPickerManager.GetColor(point.X, point.Y);
|
||||
|
||||
if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
|
||||
{
|
||||
_viewModel.SelectedItems.OfType<DesignerItemViewModelBase>().ToList().ForEach(p =>
|
||||
{
|
||||
p.Left = currentPoint.X;
|
||||
p.Top = currentPoint.Y;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (SourceConnector != null)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
partialConnection.SinkConnectorInfo = new PartCreatedConnectionInfo(currentPoint);
|
||||
HitTesting(currentPoint);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// if mouse button is not pressed we have no drag operation, ...
|
||||
if (e.LeftButton != MouseButtonState.Pressed && _service.DrawModeViewModel.GetDrawMode() != DrawMode.DirectLine)
|
||||
rubberbandSelectionStartPoint = null;
|
||||
|
||||
// ... but if mouse button is pressed and start
|
||||
// point value is set we do have one
|
||||
if (this.rubberbandSelectionStartPoint.HasValue)
|
||||
{
|
||||
// create rubberband adorner
|
||||
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
|
||||
if (adornerLayer != null)
|
||||
{
|
||||
RubberbandAdorner adorner = new RubberbandAdorner(this, rubberbandSelectionStartPoint);
|
||||
if (adorner != null)
|
||||
{
|
||||
adornerLayer.Add(adorner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseUp(e);
|
||||
|
||||
if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mediator.Instance.NotifyColleagues<bool>("DoneDrawingMessage", true);
|
||||
|
||||
if (sourceConnector != null)
|
||||
{
|
||||
FullyCreatedConnectorInfo sourceDataItem = sourceConnectorInfo ?? (sourceConnector.DataContext as FullyCreatedConnectorInfo);
|
||||
if (connectorsHit.Count() == 2)
|
||||
{
|
||||
Connector sinkConnector = connectorsHit.Last();
|
||||
FullyCreatedConnectorInfo sinkDataItem = sinkConnector.DataContext as FullyCreatedConnectorInfo;
|
||||
|
||||
int indexOfLastTempConnection = sinkDataItem.DataItem.Parent.Items.Count - 1;
|
||||
sinkDataItem.DataItem.Parent.DirectRemoveItemCommand.Execute(
|
||||
sinkDataItem.DataItem.Parent.Items[indexOfLastTempConnection]);
|
||||
sinkDataItem.DataItem.Parent.AddItemCommand.Execute(new ConnectorViewModel(sourceDataItem, sinkDataItem, _service.DrawModeViewModel.VectorLineDrawMode));
|
||||
}
|
||||
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.ConnectingLine && connectorsHit.Count() == 1)
|
||||
{
|
||||
LinkPointDesignerItemViewModel pointItemView = new LinkPointDesignerItemViewModel(e.GetPosition(this));
|
||||
FullyCreatedConnectorInfo sinkDataItem = pointItemView.TopConnector;
|
||||
|
||||
int indexOfLastTempConnection = _viewModel.Items.Count - 1;
|
||||
_viewModel.DirectRemoveItemCommand.Execute(_viewModel.Items[indexOfLastTempConnection]);
|
||||
_viewModel.DirectAddItemCommand.Execute(pointItemView);
|
||||
|
||||
var connector = new ConnectorViewModel(sourceDataItem, sinkDataItem, _service.DrawModeViewModel.VectorLineDrawMode);
|
||||
_viewModel.AddItemCommand.Execute(connector);
|
||||
|
||||
sourceDataItem.DataItem.ZIndex++;
|
||||
connector.ZIndex--;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Need to remove last item as we did not finish drawing the path
|
||||
int indexOfLastTempConnection = sourceDataItem.DataItem.Parent.Items.Count - 1;
|
||||
sourceDataItem.DataItem.Parent.DirectRemoveItemCommand.Execute(
|
||||
sourceDataItem.DataItem.Parent.Items[indexOfLastTempConnection]);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
connectorsHit = new List<Connector>();
|
||||
sourceConnector = null;
|
||||
sourceConnectorInfo = null;
|
||||
|
||||
_service.DrawModeViewModel.ResetDrawMode();
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyDown(e);
|
||||
|
||||
if (e.Key == Key.Left)
|
||||
{
|
||||
if (_viewModel.SelectedItems != null)
|
||||
{
|
||||
foreach(var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.Left -= 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.Key == Key.Right)
|
||||
{
|
||||
if (_viewModel.SelectedItems != null)
|
||||
{
|
||||
foreach (var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.Left += 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.Key == Key.Up)
|
||||
{
|
||||
if (_viewModel.SelectedItems != null)
|
||||
{
|
||||
foreach (var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.Top -= 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.Key == Key.Down)
|
||||
{
|
||||
if (_viewModel.SelectedItems != null)
|
||||
{
|
||||
foreach (var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.Top += 0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
Size size = new Size();
|
||||
foreach (UIElement element in this.InternalChildren)
|
||||
{
|
||||
double left = Canvas.GetLeft(element);
|
||||
double top = Canvas.GetTop(element);
|
||||
left = double.IsNaN(left) ? 0 : left;
|
||||
top = double.IsNaN(top) ? 0 : top;
|
||||
|
||||
//measure desired size for each child
|
||||
element.Measure(constraint);
|
||||
|
||||
Size desiredSize = element.DesiredSize;
|
||||
if (!double.IsNaN(desiredSize.Width) && !double.IsNaN(desiredSize.Height))
|
||||
{
|
||||
size.Width = Math.Max(size.Width, left + desiredSize.Width);
|
||||
size.Height = Math.Max(size.Height, top + desiredSize.Height);
|
||||
}
|
||||
}
|
||||
// add margin
|
||||
size.Width += 10;
|
||||
size.Height += 10;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private void HitTesting(Point hitPoint)
|
||||
{
|
||||
DependencyObject hitObject = this.InputHitTest(hitPoint) as DependencyObject;
|
||||
while (hitObject != null &&
|
||||
hitObject.GetType() != typeof(DesignerCanvas))
|
||||
{
|
||||
if (hitObject is Connector)
|
||||
{
|
||||
if (connectorsHit.Any(p => p.Name == "占位"))
|
||||
{
|
||||
connectorsHit.Remove(connectorsHit.FirstOrDefault(p => p.Name == "占位"));
|
||||
}
|
||||
if (!connectorsHit.Contains(hitObject as Connector))
|
||||
connectorsHit.Add(hitObject as Connector);
|
||||
}
|
||||
hitObject = VisualTreeHelper.GetParent(hitObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void OnDrop(DragEventArgs e)
|
||||
{
|
||||
base.OnDrop(e);
|
||||
DragObject dragObject = e.Data.GetData(typeof(DragObject)) as DragObject;
|
||||
if (dragObject != null)
|
||||
{
|
||||
(DataContext as IDiagramViewModel).ClearSelectedItemsCommand.Execute(null);
|
||||
Point position = e.GetPosition(this);
|
||||
DesignerItemViewModelBase itemBase = null;
|
||||
if (dragObject.DesignerItem != null)
|
||||
{
|
||||
itemBase = (DesignerItemViewModelBase)Activator.CreateInstance(dragObject.ContentType, null, dragObject.DesignerItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemBase = (DesignerItemViewModelBase)Activator.CreateInstance(dragObject.ContentType);
|
||||
itemBase.Icon = dragObject.Icon;
|
||||
itemBase.ColorViewModel = CopyHelper.Mapper(dragObject.ColorViewModel);
|
||||
}
|
||||
itemBase.Left = Math.Max(0, position.X - itemBase.ItemWidth / 2);
|
||||
itemBase.Top = Math.Max(0, position.Y - itemBase.ItemHeight / 2);
|
||||
(DataContext as IDiagramViewModel).AddItemCommand.Execute(itemBase);
|
||||
}
|
||||
var dragFile = e.Data.GetData(DataFormats.FileDrop);
|
||||
if (dragFile != null && dragFile is string[] files)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
(DataContext as IDiagramViewModel).ClearSelectedItemsCommand.Execute(null);
|
||||
Point position = e.GetPosition(this);
|
||||
ImageItemViewModel itemBase = new ImageItemViewModel();
|
||||
itemBase.Icon = file;
|
||||
itemBase.Suffix = System.IO.Path.GetExtension(itemBase.Icon).ToLower();
|
||||
itemBase.InitWidthAndHeight();
|
||||
itemBase.AutoSize();
|
||||
|
||||
itemBase.Left = Math.Max(0, position.X - itemBase.ItemWidth / 2);
|
||||
itemBase.Top = Math.Max(0, position.Y - itemBase.ItemHeight / 2);
|
||||
(DataContext as IDiagramViewModel).AddItemCommand.Execute(itemBase);
|
||||
}
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
110
AIStudio.Wpf.DiagramDesigner/Controls/DragThumb.cs
Normal file
110
AIStudio.Wpf.DiagramDesigner/Controls/DragThumb.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Controls
|
||||
{
|
||||
public class DragThumb : Thumb
|
||||
{
|
||||
public DragThumb()
|
||||
{
|
||||
base.DragDelta += new DragDeltaEventHandler(DragThumb_DragDelta);
|
||||
base.DragStarted += DragThumb_DragStarted;
|
||||
base.DragCompleted += DragThumb_DragCompleted;
|
||||
}
|
||||
|
||||
private List<SelectableDesignerItemViewModelBase> designerItems;
|
||||
|
||||
private void DragThumb_DragStarted(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
SelectableDesignerItemViewModelBase designerItem = this.DataContext as SelectableDesignerItemViewModelBase;
|
||||
|
||||
if (designerItem != null && designerItem.IsSelected)
|
||||
{
|
||||
// we only move DesignerItems
|
||||
designerItems = designerItem.SelectedItems.ToList();
|
||||
if (designerItem is ConnectorViewModel connector)
|
||||
{
|
||||
designerItems.Add(connector.SourceConnectorInfo.DataItem);
|
||||
designerItems.Add((connector.SinkConnectorInfo as FullyCreatedConnectorInfo).DataItem);
|
||||
|
||||
if (designerItem.OutTextItem != null)
|
||||
{
|
||||
designerItems.Remove(designerItem.OutTextItem);//这个自动计算位置
|
||||
}
|
||||
}
|
||||
|
||||
if (designerItem is PointDesignerItemViewModel)
|
||||
{
|
||||
designerItems = new List<SelectableDesignerItemViewModelBase> { designerItem };
|
||||
}
|
||||
|
||||
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.BeginDo = true;
|
||||
item.SetOldValue(item.Left, nameof(item.Left));
|
||||
item.SetOldValue(item.Top, nameof(item.Top));
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
designerItems = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void DragThumb_DragCompleted(object sender, DragCompletedEventArgs e)
|
||||
{
|
||||
if (designerItems != null)
|
||||
{
|
||||
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.SetCellAlignment();
|
||||
item.BeginDo = false;
|
||||
item.RaiseTopLeft();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DragThumb_DragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
if (designerItems != null)
|
||||
{
|
||||
double minLeft = double.MaxValue;
|
||||
double minTop = double.MaxValue;
|
||||
|
||||
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
double left = item.Left;
|
||||
double top = item.Top;
|
||||
minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);
|
||||
minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);
|
||||
|
||||
double deltaHorizontal = Math.Max(-minLeft, e.HorizontalChange);
|
||||
double deltaVertical = Math.Max(-minTop, e.VerticalChange);
|
||||
item.Left += deltaHorizontal;
|
||||
item.Top += deltaVertical;
|
||||
}
|
||||
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private DesignerCanvas GetDesignerCanvas(DependencyObject element)
|
||||
{
|
||||
while (element != null && !(element is DesignerCanvas))
|
||||
element = VisualTreeHelper.GetParent(element);
|
||||
|
||||
return element as DesignerCanvas;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
AIStudio.Wpf.DiagramDesigner/Controls/PointConnector.cs
Normal file
20
AIStudio.Wpf.DiagramDesigner/Controls/PointConnector.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class PointConnector : Control
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
54
AIStudio.Wpf.DiagramDesigner/Controls/PointDragThumb.cs
Normal file
54
AIStudio.Wpf.DiagramDesigner/Controls/PointDragThumb.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Controls
|
||||
{
|
||||
public class PointDragThumb : Thumb
|
||||
{
|
||||
public PointDragThumb()
|
||||
{
|
||||
base.DragDelta += new DragDeltaEventHandler(DragThumb_DragDelta);
|
||||
base.DragStarted += DragThumb_DragStarted;
|
||||
base.DragCompleted += DragThumb_DragCompleted;
|
||||
}
|
||||
|
||||
|
||||
private void DragThumb_DragStarted(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void DragThumb_DragCompleted(object sender, DragCompletedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DragThumb_DragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
if (this.DataContext is PointInfoBase point)
|
||||
{
|
||||
double minLeft = double.MaxValue;
|
||||
double minTop = double.MaxValue;
|
||||
|
||||
double left = point.X;
|
||||
double top = point.Y;
|
||||
minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);
|
||||
minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);
|
||||
|
||||
double deltaHorizontal = Math.Max(-minLeft, e.HorizontalChange);
|
||||
double deltaVertical = Math.Max(-minTop, e.VerticalChange);
|
||||
|
||||
point.X += deltaHorizontal;
|
||||
point.Y += deltaVertical;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class RelativePositionPanel : Panel
|
||||
{
|
||||
public static readonly DependencyProperty RelativePositionProperty =
|
||||
DependencyProperty.RegisterAttached("RelativePosition", typeof(Point), typeof(RelativePositionPanel),
|
||||
new FrameworkPropertyMetadata(new Point(0, 0),
|
||||
new PropertyChangedCallback(RelativePositionPanel.OnRelativePositionChanged)));
|
||||
|
||||
public static Point GetRelativePosition(UIElement element)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
throw new ArgumentNullException("element");
|
||||
}
|
||||
return (Point)element.GetValue(RelativePositionProperty);
|
||||
}
|
||||
|
||||
public static void SetRelativePosition(UIElement element, Point value)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
throw new ArgumentNullException("element");
|
||||
}
|
||||
element.SetValue(RelativePositionProperty, value);
|
||||
}
|
||||
|
||||
private static void OnRelativePositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
UIElement reference = d as UIElement;
|
||||
if (reference != null)
|
||||
{
|
||||
RelativePositionPanel parent = VisualTreeHelper.GetParent(reference) as RelativePositionPanel;
|
||||
if (parent != null)
|
||||
{
|
||||
parent.InvalidateArrange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override Size ArrangeOverride(Size arrangeSize)
|
||||
{
|
||||
foreach (UIElement element in base.InternalChildren)
|
||||
{
|
||||
if (element != null)
|
||||
{
|
||||
Point relPosition = GetRelativePosition(element);
|
||||
double x = (arrangeSize.Width - element.DesiredSize.Width) * relPosition.X;
|
||||
double y = (arrangeSize.Height - element.DesiredSize.Height) * relPosition.Y;
|
||||
|
||||
if (double.IsNaN(x)) x = 0;
|
||||
if (double.IsNaN(y)) y = 0;
|
||||
|
||||
element.Arrange(new Rect(new Point(x, y), element.DesiredSize));
|
||||
}
|
||||
}
|
||||
return arrangeSize;
|
||||
}
|
||||
|
||||
protected override Size MeasureOverride(Size availableSize)
|
||||
{
|
||||
Size size = new Size(double.PositiveInfinity, double.PositiveInfinity);
|
||||
|
||||
// SDK docu says about InternalChildren Property: 'Classes that are derived from Panel
|
||||
// should use this property, instead of the Children property, for internal overrides
|
||||
// such as MeasureCore and ArrangeCore.
|
||||
|
||||
foreach (UIElement element in this.InternalChildren)
|
||||
{
|
||||
if (element != null)
|
||||
element.Measure(size);
|
||||
}
|
||||
|
||||
return base.MeasureOverride(availableSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
196
AIStudio.Wpf.DiagramDesigner/Controls/ResizeThumb.cs
Normal file
196
AIStudio.Wpf.DiagramDesigner/Controls/ResizeThumb.cs
Normal file
@@ -0,0 +1,196 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Controls
|
||||
{
|
||||
public class ResizeThumb : Thumb
|
||||
{
|
||||
public ResizeThumb()
|
||||
{
|
||||
base.DragDelta += new DragDeltaEventHandler(ResizeThumb_DragDelta);
|
||||
base.DragStarted += ResizeThumb_DragStarted;
|
||||
base.DragCompleted += ResizeThumb_DragCompleted;
|
||||
}
|
||||
|
||||
private List<SelectableDesignerItemViewModelBase> designerItems;
|
||||
IDiagramViewModel diagarmViewModel;
|
||||
|
||||
private void ResizeThumb_DragStarted(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
DesignerItemViewModelBase designerItem = this.DataContext as DesignerItemViewModelBase;
|
||||
diagarmViewModel = designerItem.Parent;
|
||||
if (designerItem != null && designerItem.IsSelected)
|
||||
{
|
||||
designerItems = designerItem.SelectedItems.ToList();
|
||||
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.BeginDo = true;
|
||||
item.SetOldValue(item.ItemWidth, nameof(item.ItemWidth));
|
||||
item.SetOldValue(item.ItemHeight, nameof(item.ItemHeight));
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
designerItems = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResizeThumb_DragCompleted(object sender, DragCompletedEventArgs e)
|
||||
{
|
||||
if (designerItems != null)
|
||||
{
|
||||
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.BeginDo = false;
|
||||
item.RaiseItemWidthHeight();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
if (designerItems != null)
|
||||
{
|
||||
double minLeft, minTop, minDeltaHorizontal, minDeltaVertical;
|
||||
double dragDeltaVertical, dragDeltaHorizontal, scale;
|
||||
|
||||
CalculateDragLimits(designerItems.OfType<DesignerItemViewModelBase>(), out minLeft, out minTop,
|
||||
out minDeltaHorizontal, out minDeltaVertical);
|
||||
|
||||
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
if (item != null && item.ParentId == Guid.Empty)
|
||||
{
|
||||
switch (base.VerticalAlignment)
|
||||
{
|
||||
case VerticalAlignment.Bottom:
|
||||
dragDeltaVertical = Math.Min(-e.VerticalChange, minDeltaVertical);
|
||||
scale = (item.ItemHeight - dragDeltaVertical) / item.ItemHeight;
|
||||
DragBottom(scale, item, diagarmViewModel.SelectionService);
|
||||
break;
|
||||
case VerticalAlignment.Top:
|
||||
double top = item.Top;
|
||||
dragDeltaVertical = Math.Min(Math.Max(-minTop, e.VerticalChange), minDeltaVertical);
|
||||
scale = (item.ItemHeight - dragDeltaVertical) / item.ItemHeight;
|
||||
DragTop(scale, item, diagarmViewModel.SelectionService);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (base.HorizontalAlignment)
|
||||
{
|
||||
case HorizontalAlignment.Left:
|
||||
double left = item.Left;
|
||||
dragDeltaHorizontal = Math.Min(Math.Max(-minLeft, e.HorizontalChange), minDeltaHorizontal);
|
||||
scale = (item.ItemWidth - dragDeltaHorizontal) / item.ItemWidth;
|
||||
DragLeft(scale, item, diagarmViewModel.SelectionService);
|
||||
break;
|
||||
case HorizontalAlignment.Right:
|
||||
dragDeltaHorizontal = Math.Min(-e.HorizontalChange, minDeltaHorizontal);
|
||||
scale = (item.ItemWidth - dragDeltaHorizontal) / item.ItemWidth;
|
||||
DragRight(scale, item, diagarmViewModel.SelectionService);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
#region Helper methods
|
||||
|
||||
private void DragLeft(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
|
||||
{
|
||||
IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
|
||||
|
||||
double groupLeft = item.Left + item.ItemWidth;
|
||||
foreach (DesignerItemViewModelBase groupItem in groupItems)
|
||||
{
|
||||
double groupItemLeft = groupItem.Left;
|
||||
double delta = (groupLeft - groupItemLeft) * (scale - 1);
|
||||
groupItem.Left = groupItemLeft - delta;
|
||||
groupItem.ItemWidth = groupItem.ItemWidth * scale;
|
||||
}
|
||||
}
|
||||
|
||||
private void DragTop(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
|
||||
{
|
||||
IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
|
||||
double groupBottom = item.Top + item.ItemHeight;
|
||||
foreach (DesignerItemViewModelBase groupItem in groupItems)
|
||||
{
|
||||
double groupItemTop = groupItem.Top;
|
||||
double delta = (groupBottom - groupItemTop) * (scale - 1);
|
||||
groupItem.Top = groupItemTop - delta;
|
||||
groupItem.ItemHeight = groupItem.ItemHeight * scale;
|
||||
}
|
||||
}
|
||||
|
||||
private void DragRight(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
|
||||
{
|
||||
IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
|
||||
|
||||
double groupLeft = item.Left;
|
||||
foreach (DesignerItemViewModelBase groupItem in groupItems)
|
||||
{
|
||||
double groupItemLeft = groupItem.Left;
|
||||
double delta = (groupItemLeft - groupLeft) * (scale - 1);
|
||||
|
||||
groupItem.Left = groupItemLeft + delta;
|
||||
groupItem.ItemWidth = groupItem.ItemWidth * scale;
|
||||
}
|
||||
}
|
||||
|
||||
private void DragBottom(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
|
||||
{
|
||||
IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
|
||||
double groupTop = item.Top;
|
||||
foreach (DesignerItemViewModelBase groupItem in groupItems)
|
||||
{
|
||||
double groupItemTop = groupItem.Top;
|
||||
double delta = (groupItemTop - groupTop) * (scale - 1);
|
||||
|
||||
groupItem.Top = groupItemTop + delta;
|
||||
groupItem.ItemHeight = groupItem.ItemHeight * scale;
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateDragLimits(IEnumerable<DesignerItemViewModelBase> selectedItems, out double minLeft, out double minTop, out double minDeltaHorizontal, out double minDeltaVertical)
|
||||
{
|
||||
minLeft = double.MaxValue;
|
||||
minTop = double.MaxValue;
|
||||
minDeltaHorizontal = double.MaxValue;
|
||||
minDeltaVertical = double.MaxValue;
|
||||
|
||||
// drag limits are set by these parameters: canvas top, canvas left, minHeight, minWidth
|
||||
// calculate min value for each parameter for each item
|
||||
foreach (DesignerItemViewModelBase item in selectedItems)
|
||||
{
|
||||
double left = item.Left;
|
||||
double top = item.Top;
|
||||
|
||||
minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);
|
||||
minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);
|
||||
|
||||
minDeltaVertical = Math.Min(minDeltaVertical, 10);
|
||||
minDeltaHorizontal = Math.Min(minDeltaHorizontal, 10);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
106
AIStudio.Wpf.DiagramDesigner/Controls/RotateThumb.cs
Normal file
106
AIStudio.Wpf.DiagramDesigner/Controls/RotateThumb.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Controls
|
||||
{
|
||||
public class RotateThumb : Thumb
|
||||
{
|
||||
private Point centerPoint;
|
||||
private Vector startVector;
|
||||
private double initialAngle;
|
||||
private Canvas designerCanvas;
|
||||
private DesignerItemViewModelBase designerItem;
|
||||
private RotateTransform rotateTransform;
|
||||
|
||||
public RotateThumb()
|
||||
{
|
||||
DragDelta += RotateThumb_DragDelta;
|
||||
DragStarted += RotateThumb_DragStarted;
|
||||
DragCompleted += RotateThumb_DragCompleted;
|
||||
}
|
||||
|
||||
private List<SelectableDesignerItemViewModelBase> designerItems;
|
||||
|
||||
private void RotateThumb_DragStarted(object sender, DragStartedEventArgs e)
|
||||
{
|
||||
this.designerItem = this.DataContext as DesignerItemViewModelBase;
|
||||
|
||||
if (this.designerItem != null)
|
||||
{
|
||||
designerItems = designerItem.SelectedItems.ToList();
|
||||
|
||||
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.BeginDo = true;
|
||||
item.SetOldValue(this.designerItem.Angle, nameof(this.designerItem.Angle));
|
||||
}
|
||||
|
||||
this.designerCanvas = GetDesignerCanvas(this);
|
||||
if (this.designerCanvas != null)
|
||||
{
|
||||
this.centerPoint =
|
||||
new Point(this.designerItem.Left + this.designerItem.ItemWidth * 0.5,
|
||||
this.designerItem.Top + this.designerItem.ItemHeight * 0.5);
|
||||
|
||||
Point startPoint = Mouse.GetPosition(this.designerCanvas);
|
||||
this.startVector = Point.Subtract(startPoint, this.centerPoint);
|
||||
|
||||
|
||||
this.initialAngle = this.designerItem.Angle;
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
designerItems = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void RotateThumb_DragCompleted(object sender, DragCompletedEventArgs e)
|
||||
{
|
||||
this.designerItem = this.DataContext as DesignerItemViewModelBase;
|
||||
|
||||
if (this.designerItems != null)
|
||||
{
|
||||
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.BeginDo = false;
|
||||
item.RaiseAngle();
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void RotateThumb_DragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
if (this.designerItems != null && this.designerCanvas != null)
|
||||
{
|
||||
Point currentPoint = Mouse.GetPosition(this.designerCanvas);
|
||||
Vector deltaVector = Point.Subtract(currentPoint, this.centerPoint);
|
||||
|
||||
double angle = Vector.AngleBetween(this.startVector, deltaVector);
|
||||
|
||||
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
|
||||
{
|
||||
item.Angle = this.initialAngle + Math.Round(angle, 0);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private DesignerCanvas GetDesignerCanvas(DependencyObject element)
|
||||
{
|
||||
while (element != null && !(element is DesignerCanvas))
|
||||
element = VisualTreeHelper.GetParent(element);
|
||||
|
||||
return element as DesignerCanvas;
|
||||
}
|
||||
}
|
||||
}
|
||||
162
AIStudio.Wpf.DiagramDesigner/Controls/ZoomBox.cs
Normal file
162
AIStudio.Wpf.DiagramDesigner/Controls/ZoomBox.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ZoomBox : Control
|
||||
{
|
||||
private Thumb zoomThumb;
|
||||
private Canvas zoomCanvas;
|
||||
private Slider zoomSlider;
|
||||
private ScaleTransform scaleTransform;
|
||||
|
||||
#region DPs
|
||||
|
||||
#region ScrollViewer
|
||||
public ScrollViewer ScrollViewer
|
||||
{
|
||||
get { return (ScrollViewer)GetValue(ScrollViewerProperty); }
|
||||
set { SetValue(ScrollViewerProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ScrollViewerProperty =
|
||||
DependencyProperty.Register("ScrollViewer", typeof(ScrollViewer), typeof(ZoomBox));
|
||||
#endregion
|
||||
|
||||
#region DesignerCanvas
|
||||
|
||||
|
||||
public static readonly DependencyProperty DesignerCanvasProperty =
|
||||
DependencyProperty.Register("DesignerCanvas", typeof(DesignerCanvas), typeof(ZoomBox),
|
||||
new FrameworkPropertyMetadata(null,
|
||||
new PropertyChangedCallback(OnDesignerCanvasChanged)));
|
||||
|
||||
|
||||
public DesignerCanvas DesignerCanvas
|
||||
{
|
||||
get { return (DesignerCanvas)GetValue(DesignerCanvasProperty); }
|
||||
set { SetValue(DesignerCanvasProperty, value); }
|
||||
}
|
||||
|
||||
|
||||
private static void OnDesignerCanvasChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
ZoomBox target = (ZoomBox)d;
|
||||
DesignerCanvas oldDesignerCanvas = (DesignerCanvas)e.OldValue;
|
||||
DesignerCanvas newDesignerCanvas = target.DesignerCanvas;
|
||||
target.OnDesignerCanvasChanged(oldDesignerCanvas, newDesignerCanvas);
|
||||
}
|
||||
|
||||
|
||||
protected virtual void OnDesignerCanvasChanged(DesignerCanvas oldDesignerCanvas, DesignerCanvas newDesignerCanvas)
|
||||
{
|
||||
if (oldDesignerCanvas != null)
|
||||
{
|
||||
newDesignerCanvas.LayoutUpdated -= new EventHandler(this.DesignerCanvas_LayoutUpdated);
|
||||
newDesignerCanvas.MouseWheel -= new MouseWheelEventHandler(this.DesignerCanvas_MouseWheel);
|
||||
}
|
||||
|
||||
if (newDesignerCanvas != null)
|
||||
{
|
||||
newDesignerCanvas.LayoutUpdated += new EventHandler(this.DesignerCanvas_LayoutUpdated);
|
||||
newDesignerCanvas.MouseWheel += new MouseWheelEventHandler(this.DesignerCanvas_MouseWheel);
|
||||
newDesignerCanvas.LayoutTransform = this.scaleTransform;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (this.ScrollViewer == null)
|
||||
return;
|
||||
|
||||
this.zoomThumb = Template.FindName("PART_ZoomThumb", this) as Thumb;
|
||||
if (this.zoomThumb == null)
|
||||
throw new Exception("PART_ZoomThumb template is missing!");
|
||||
|
||||
this.zoomCanvas = Template.FindName("PART_ZoomCanvas", this) as Canvas;
|
||||
if (this.zoomCanvas == null)
|
||||
throw new Exception("PART_ZoomCanvas template is missing!");
|
||||
|
||||
this.zoomSlider = Template.FindName("PART_ZoomSlider", this) as Slider;
|
||||
if (this.zoomSlider == null)
|
||||
throw new Exception("PART_ZoomSlider template is missing!");
|
||||
|
||||
this.zoomThumb.DragDelta += new DragDeltaEventHandler(this.Thumb_DragDelta);
|
||||
this.zoomSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(this.ZoomSlider_ValueChanged);
|
||||
this.scaleTransform = new ScaleTransform();
|
||||
}
|
||||
|
||||
private void ZoomSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
double scale = e.NewValue / e.OldValue;
|
||||
double halfViewportHeight = this.ScrollViewer.ViewportHeight / 2;
|
||||
double newVerticalOffset = ((this.ScrollViewer.VerticalOffset + halfViewportHeight) * scale - halfViewportHeight);
|
||||
double halfViewportWidth = this.ScrollViewer.ViewportWidth / 2;
|
||||
double newHorizontalOffset = ((this.ScrollViewer.HorizontalOffset + halfViewportWidth) * scale - halfViewportWidth);
|
||||
this.scaleTransform.ScaleX *= scale;
|
||||
this.scaleTransform.ScaleY *= scale;
|
||||
this.ScrollViewer.ScrollToHorizontalOffset(newHorizontalOffset);
|
||||
this.ScrollViewer.ScrollToVerticalOffset(newVerticalOffset);
|
||||
}
|
||||
|
||||
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
|
||||
{
|
||||
double scale, xOffset, yOffset;
|
||||
this.InvalidateScale(out scale, out xOffset, out yOffset);
|
||||
this.ScrollViewer.ScrollToHorizontalOffset(this.ScrollViewer.HorizontalOffset + e.HorizontalChange / scale);
|
||||
this.ScrollViewer.ScrollToVerticalOffset(this.ScrollViewer.VerticalOffset + e.VerticalChange / scale);
|
||||
}
|
||||
|
||||
private void DesignerCanvas_LayoutUpdated(object sender, EventArgs e)
|
||||
{
|
||||
//htzk
|
||||
try
|
||||
{
|
||||
|
||||
double scale, xOffset, yOffset;
|
||||
this.InvalidateScale(out scale, out xOffset, out yOffset);
|
||||
this.zoomThumb.Width = this.ScrollViewer.ViewportWidth * scale;
|
||||
this.zoomThumb.Height = this.ScrollViewer.ViewportHeight * scale;
|
||||
Canvas.SetLeft(this.zoomThumb, xOffset + this.ScrollViewer.HorizontalOffset * scale);
|
||||
Canvas.SetTop(this.zoomThumb, yOffset + this.ScrollViewer.VerticalOffset * scale);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void DesignerCanvas_MouseWheel(object sender, EventArgs e)
|
||||
{
|
||||
MouseWheelEventArgs wheel = (MouseWheelEventArgs)e;
|
||||
|
||||
//divide the value by 10 so that it is more smooth
|
||||
double value = Math.Max(0, wheel.Delta / 10);
|
||||
value = Math.Min(wheel.Delta, 10);
|
||||
this.zoomSlider.Value += value;
|
||||
}
|
||||
|
||||
private void InvalidateScale(out double scale, out double xOffset, out double yOffset)
|
||||
{
|
||||
double w = DesignerCanvas.ActualWidth * this.scaleTransform.ScaleX;
|
||||
double h = DesignerCanvas.ActualHeight * this.scaleTransform.ScaleY;
|
||||
|
||||
// zoom canvas size
|
||||
double x = this.zoomCanvas.ActualWidth;
|
||||
double y = this.zoomCanvas.ActualHeight;
|
||||
double scaleX = x / w;
|
||||
double scaleY = y / h;
|
||||
scale = (scaleX < scaleY) ? scaleX : scaleY;
|
||||
xOffset = (x - scale * w) / 2;
|
||||
yOffset = (y - scale * h) / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
|
||||
public class ArrowPathConverter : IValueConverter
|
||||
{
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value is ArrowPathStyle arrowStyle)
|
||||
{
|
||||
return ArrowPathData.Arrow[(int)arrowStyle];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ArrowSizeConverter : IValueConverter
|
||||
{
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value is ArrowSizeStyle arrowStyle)
|
||||
{
|
||||
return (int)arrowStyle;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
[ValueConversion(typeof(bool), typeof(Visibility))]
|
||||
public class BoolToVisibilityConverter : IValueConverter
|
||||
{
|
||||
static BoolToVisibilityConverter()
|
||||
{
|
||||
Instance = new BoolToVisibilityConverter();
|
||||
}
|
||||
|
||||
public static BoolToVisibilityConverter Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
return ((bool)value) ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
78
AIStudio.Wpf.DiagramDesigner/Converters/ClipConverter.cs
Normal file
78
AIStudio.Wpf.DiagramDesigner/Converters/ClipConverter.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ClipConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
string para = parameter?.ToString();
|
||||
try
|
||||
{
|
||||
if (value is ImageItemViewModel imageItemViewModel)
|
||||
{
|
||||
double xradio = imageItemViewModel.ItemWidth / imageItemViewModel.ImageWidth;
|
||||
double yradio = imageItemViewModel.ItemHeight / imageItemViewModel.ImageHeight;
|
||||
if (para == "Clip")
|
||||
{
|
||||
if (imageItemViewModel.ClipMode == ClipMode.RectangleGeometry)
|
||||
{
|
||||
RectangleGeometry rectangle = new RectangleGeometry();
|
||||
if (imageItemViewModel.ResizeMode == false)
|
||||
{
|
||||
rectangle.Rect = new System.Windows.Rect(imageItemViewModel.ResizeMargin.Left * xradio, imageItemViewModel.ResizeMargin.Top * yradio, imageItemViewModel.ItemWidth, imageItemViewModel.ItemHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
rectangle.Rect = new System.Windows.Rect(imageItemViewModel.ResizeMargin.Left, imageItemViewModel.ResizeMargin.Top , imageItemViewModel.ItemWidth - (imageItemViewModel.ResizeMargin.Left + imageItemViewModel.ResizeMargin.Right), imageItemViewModel.ItemHeight - (imageItemViewModel.ResizeMargin.Top + imageItemViewModel.ResizeMargin.Bottom));
|
||||
}
|
||||
return rectangle;
|
||||
}
|
||||
else if (imageItemViewModel.ClipMode == ClipMode.EllipseGeometry)
|
||||
{
|
||||
EllipseGeometry ellipse = new EllipseGeometry();
|
||||
if (imageItemViewModel.ResizeMode == false)
|
||||
{
|
||||
ellipse.Center = new Point(imageItemViewModel.ResizeMargin.Left * xradio + imageItemViewModel.ItemWidth / 2, imageItemViewModel.ResizeMargin.Top * yradio + imageItemViewModel.ItemHeight / 2);
|
||||
ellipse.RadiusX = imageItemViewModel.ItemWidth / 2;
|
||||
ellipse.RadiusY = imageItemViewModel.ItemHeight / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ellipse.Center = new Point(imageItemViewModel.ResizeMargin.Left + (imageItemViewModel.ItemWidth - imageItemViewModel.ResizeMargin.Left - imageItemViewModel.ResizeMargin.Right) / 2, imageItemViewModel.ResizeMargin.Top + (imageItemViewModel.ItemHeight - imageItemViewModel.ResizeMargin.Top - imageItemViewModel.ResizeMargin.Bottom)/ 2);
|
||||
ellipse.RadiusX = (imageItemViewModel.ItemWidth - imageItemViewModel.ResizeMargin.Left - imageItemViewModel.ResizeMargin.Right) / 2;
|
||||
ellipse.RadiusY = (imageItemViewModel.ItemHeight - imageItemViewModel.ResizeMargin.Top - imageItemViewModel.ResizeMargin.Bottom) / 2;
|
||||
}
|
||||
return ellipse;
|
||||
}
|
||||
}
|
||||
else if (para == "Margin")
|
||||
{
|
||||
if (imageItemViewModel.ResizeMode == false)
|
||||
{
|
||||
return new Thickness(-imageItemViewModel.ResizeMargin.Left * xradio, -imageItemViewModel.ResizeMargin.Top * yradio, -imageItemViewModel.ResizeMargin.Right * xradio, -imageItemViewModel.ResizeMargin.Bottom * yradio);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Thickness();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
218
AIStudio.Wpf.DiagramDesigner/Converters/ColorBrushConverter.cs
Normal file
218
AIStudio.Wpf.DiagramDesigner/Converters/ColorBrushConverter.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ColorBrushConverter : IValueConverter
|
||||
{
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
Brush brush = null;
|
||||
if (value is Color)
|
||||
{
|
||||
brush = new SolidColorBrush((Color)value);
|
||||
}
|
||||
else if (value is ColorObject colorObject)
|
||||
{
|
||||
if (colorObject.BrushType == BrushType.None)
|
||||
brush = new SolidColorBrush(Colors.Transparent);
|
||||
else if (colorObject.BrushType == BrushType.SolidColorBrush)
|
||||
brush = new SolidColorBrush(colorObject.Color);
|
||||
else if (colorObject.BrushType == BrushType.LinearGradientBrush)
|
||||
{
|
||||
Point startPoint;
|
||||
Point endPoint;
|
||||
if (colorObject.LinearOrientation == LinearOrientation.LeftToRight)
|
||||
{
|
||||
startPoint = new Point(0, 0.5);
|
||||
endPoint = new Point(1, 0.5);
|
||||
}
|
||||
else if (colorObject.LinearOrientation == LinearOrientation.LeftTopToRightBottom)
|
||||
{
|
||||
startPoint = new Point(0, 0);
|
||||
endPoint = new Point(1, 1);
|
||||
}
|
||||
else if (colorObject.LinearOrientation == LinearOrientation.TopToBottom)
|
||||
{
|
||||
startPoint = new Point(0.5, 0);
|
||||
endPoint = new Point(0.5, 1);
|
||||
}
|
||||
else if (colorObject.LinearOrientation == LinearOrientation.RightTopToLeftBottom)
|
||||
{
|
||||
startPoint = new Point(1, 0);
|
||||
endPoint = new Point(0, 1);
|
||||
}
|
||||
else if (colorObject.LinearOrientation == LinearOrientation.RightToLeft)
|
||||
{
|
||||
startPoint = new Point(1, 0.5);
|
||||
endPoint = new Point(0, 0.5);
|
||||
}
|
||||
else if (colorObject.LinearOrientation == LinearOrientation.RightBottomToLeftTop)
|
||||
{
|
||||
startPoint = new Point(1, 1);
|
||||
endPoint = new Point(0, 0);
|
||||
}
|
||||
else if (colorObject.LinearOrientation == LinearOrientation.BottomToTop)
|
||||
{
|
||||
startPoint = new Point(0.5, 1);
|
||||
endPoint = new Point(0.5, 0);
|
||||
}
|
||||
else if (colorObject.LinearOrientation == LinearOrientation.LeftBottomToRightTop)
|
||||
{
|
||||
startPoint = new Point(0, 1);
|
||||
endPoint = new Point(1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
startPoint = new Point(0, 0.5);
|
||||
endPoint = new Point(1, 0.5);
|
||||
}
|
||||
|
||||
LinearGradientBrush myBrush = new LinearGradientBrush();
|
||||
myBrush.StartPoint = startPoint;
|
||||
myBrush.EndPoint = endPoint;
|
||||
if (colorObject.GradientStop != null)
|
||||
{
|
||||
foreach (var stop in colorObject.GradientStop)
|
||||
{
|
||||
myBrush.GradientStops.Add(new System.Windows.Media.GradientStop(stop.Color, stop.Offset));
|
||||
}
|
||||
}
|
||||
brush = myBrush;
|
||||
|
||||
RotateTransform rotateTransform = new RotateTransform(colorObject.Angle, 0.5, 0.5);
|
||||
myBrush.RelativeTransform = rotateTransform;
|
||||
}
|
||||
else if (colorObject.BrushType == BrushType.RadialGradientBrush)
|
||||
{
|
||||
Point center;
|
||||
Point gradientOrigin;
|
||||
double radiusX;
|
||||
double radiusY;
|
||||
|
||||
if (colorObject.RadialOrientation == RadialOrientation.LeftTop)
|
||||
{
|
||||
center = new Point(0, 0);
|
||||
gradientOrigin = center;
|
||||
radiusX = 1;
|
||||
radiusY = 1;
|
||||
}
|
||||
else if (colorObject.RadialOrientation == RadialOrientation.RightTop)
|
||||
{
|
||||
center = new Point(1, 0);
|
||||
gradientOrigin = center;
|
||||
radiusX = 1;
|
||||
radiusY = 1;
|
||||
}
|
||||
else if (colorObject.RadialOrientation == RadialOrientation.RightBottom)
|
||||
{
|
||||
center = new Point(1, 1);
|
||||
gradientOrigin = center;
|
||||
radiusX = 1;
|
||||
radiusY = 1;
|
||||
}
|
||||
else if (colorObject.RadialOrientation == RadialOrientation.LeftBottom)
|
||||
{
|
||||
center = new Point(0, 1);
|
||||
gradientOrigin = center;
|
||||
radiusX = 1;
|
||||
radiusY = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
center = new Point(0.5, 0.5);
|
||||
gradientOrigin = center;
|
||||
radiusX = 0.5;
|
||||
radiusY = 0.5;
|
||||
}
|
||||
|
||||
RadialGradientBrush myBrush = new RadialGradientBrush();
|
||||
myBrush.Center = center;
|
||||
myBrush.GradientOrigin = gradientOrigin;
|
||||
myBrush.RadiusX = radiusX;
|
||||
myBrush.RadiusY = radiusY;
|
||||
if (colorObject.GradientStop != null)
|
||||
{
|
||||
foreach (var stop in colorObject.GradientStop)
|
||||
{
|
||||
myBrush.GradientStops.Add(new System.Windows.Media.GradientStop(stop.Color, stop.Offset));
|
||||
}
|
||||
}
|
||||
brush = myBrush;
|
||||
|
||||
RotateTransform rotateTransform = new RotateTransform(colorObject.Angle, 0.5, 0.5);
|
||||
myBrush.RelativeTransform = rotateTransform;
|
||||
}
|
||||
else if (colorObject.BrushType == BrushType.ImageBrush)
|
||||
{
|
||||
ImageBrush myBrush = new ImageBrush();
|
||||
myBrush.ImageSource = new BitmapImage(new Uri(colorObject.Image, UriKind.Absolute));
|
||||
brush = myBrush;
|
||||
}
|
||||
else if (colorObject.BrushType == BrushType.DrawingBrush)
|
||||
{
|
||||
DrawingBrush myBrush = new DrawingBrush();
|
||||
|
||||
GeometryDrawing backgroundSquare =
|
||||
new GeometryDrawing(
|
||||
Brushes.White,
|
||||
null,
|
||||
new RectangleGeometry(new Rect(0, 0, 100, 100)));
|
||||
|
||||
GeometryGroup aGeometryGroup = new GeometryGroup();
|
||||
aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(0, 0, 50, 50)));
|
||||
aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(50, 50, 50, 50)));
|
||||
|
||||
LinearGradientBrush checkerBrush = new LinearGradientBrush();
|
||||
checkerBrush.GradientStops.Add(new System.Windows.Media.GradientStop(Colors.Black, 0.0));
|
||||
checkerBrush.GradientStops.Add(new System.Windows.Media.GradientStop(Colors.Gray, 1.0));
|
||||
|
||||
GeometryDrawing checkers = new GeometryDrawing(checkerBrush, null, aGeometryGroup);
|
||||
|
||||
DrawingGroup checkersDrawingGroup = new DrawingGroup();
|
||||
checkersDrawingGroup.Children.Add(backgroundSquare);
|
||||
checkersDrawingGroup.Children.Add(checkers);
|
||||
|
||||
myBrush.Drawing = checkersDrawingGroup;
|
||||
myBrush.Viewport = new Rect(0, 0, 0.25, 0.25);
|
||||
myBrush.TileMode = TileMode.Tile;
|
||||
|
||||
brush = myBrush;
|
||||
}
|
||||
if (brush != null)
|
||||
{
|
||||
brush.Opacity = colorObject.Opacity;
|
||||
}
|
||||
}
|
||||
else if (value is ObservableCollection<GradientStop> gradientStop)
|
||||
{
|
||||
LinearGradientBrush myBrush = new LinearGradientBrush();
|
||||
myBrush.StartPoint = new Point(0, 0.5);
|
||||
myBrush.EndPoint = new Point(1, 0.5);
|
||||
if (gradientStop != null)
|
||||
{
|
||||
foreach (var stop in gradientStop)
|
||||
{
|
||||
myBrush.GradientStops.Add(new System.Windows.Media.GradientStop(stop.Color, stop.Offset));
|
||||
}
|
||||
}
|
||||
brush = myBrush;
|
||||
}
|
||||
|
||||
return brush;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ConectorOrientationConverter : IValueConverter
|
||||
{
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value is string)
|
||||
{
|
||||
string str = value as string;
|
||||
|
||||
return -5 - (str.Length * 4);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ConectorValueConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (values == null || values.Length < 1)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
if (values[0] is double && values[1] is ValueTypePoint)
|
||||
{
|
||||
double connectorValue = (double)values[0];
|
||||
ValueTypePoint valueTypePoint = (ValueTypePoint)values[1];
|
||||
|
||||
if (valueTypePoint == ValueTypePoint.Bool)
|
||||
{
|
||||
return (connectorValue == 0) ? "F" : "T";
|
||||
}
|
||||
else if (valueTypePoint == ValueTypePoint.Int)
|
||||
{
|
||||
return connectorValue.ToString("0");
|
||||
}
|
||||
else
|
||||
{
|
||||
return connectorValue.ToString("f3");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ConnectionDataConverter : IMultiValueConverter
|
||||
{
|
||||
static ConnectionDataConverter()
|
||||
{
|
||||
Instance = new ConnectionDataConverter();
|
||||
}
|
||||
|
||||
public static ConnectionDataConverter Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
List<PointInfoBase> points = (List<PointInfoBase>)values[0];
|
||||
PathGeometry pathGeometry = new PathGeometry();
|
||||
PathFigure figure = new PathFigure();
|
||||
figure.StartPoint = points[0];
|
||||
if (values[1]?.ToString() == DrawMode.RadiusConnectingLine.ToString())
|
||||
{
|
||||
for (var i = 0; i < points.Count - 1; i++)
|
||||
{
|
||||
int current = i, last = i - 1, next = i + 1, next2 = i + 2;
|
||||
if (last == -1)
|
||||
{
|
||||
last = 0;
|
||||
}
|
||||
if (next == points.Count)
|
||||
{
|
||||
next = points.Count - 1;
|
||||
}
|
||||
if (next2 == points.Count)
|
||||
{
|
||||
next2 = points.Count - 1;
|
||||
}
|
||||
var bzs = SegmentHelper.GetBezierSegment(points[current], points[last], points[next], points[next2]);
|
||||
figure.Segments.Add(bzs);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
{
|
||||
|
||||
LineSegment arc = new LineSegment(points[i], true);
|
||||
figure.Segments.Add(arc);
|
||||
}
|
||||
}
|
||||
|
||||
pathGeometry.Figures.Add(figure);
|
||||
return pathGeometry;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
[ValueConversion(typeof(List<Point>), typeof(PathSegmentCollection))]
|
||||
public class ConnectionPathConverter : IValueConverter
|
||||
{
|
||||
static ConnectionPathConverter()
|
||||
{
|
||||
Instance = new ConnectionPathConverter();
|
||||
}
|
||||
|
||||
public static ConnectionPathConverter Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
List<PointInfoBase> points = (List<PointInfoBase>)value;
|
||||
PointCollection pointCollection = new PointCollection();
|
||||
if (points != null)
|
||||
{
|
||||
foreach (var point in points)
|
||||
{
|
||||
pointCollection.Add(point);
|
||||
}
|
||||
}
|
||||
return pointCollection;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
85
AIStudio.Wpf.DiagramDesigner/Converters/DoubleToThickness.cs
Normal file
85
AIStudio.Wpf.DiagramDesigner/Converters/DoubleToThickness.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class DoubleToThickness : IValueConverter
|
||||
{
|
||||
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (parameter != null)
|
||||
{
|
||||
switch (parameter.ToString())
|
||||
{
|
||||
case "Left":
|
||||
return new Thickness(System.Convert.ToDouble(value), 0, 0, 0);
|
||||
|
||||
case "Top":
|
||||
return new Thickness(0, System.Convert.ToDouble(value), 0, 0);
|
||||
|
||||
case "Right":
|
||||
return new Thickness(0, 0, System.Convert.ToDouble(value), 0);
|
||||
|
||||
case "Buttom":
|
||||
return new Thickness(0, 0, 0, System.Convert.ToDouble(value));
|
||||
|
||||
case "LeftTop":
|
||||
return new Thickness(System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0, 0);
|
||||
|
||||
case "LeftButtom":
|
||||
return new Thickness(System.Convert.ToDouble(value), 0, 0, System.Convert.ToDouble(value));
|
||||
|
||||
case "RightTop":
|
||||
return new Thickness(0, System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0);
|
||||
|
||||
case "RigthButtom":
|
||||
return new Thickness(0, 0, System.Convert.ToDouble(value), System.Convert.ToDouble(value));
|
||||
|
||||
case "LeftRight":
|
||||
return new Thickness(System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value), 0);
|
||||
|
||||
case "TopButtom":
|
||||
return new Thickness(0, System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value));
|
||||
|
||||
default:
|
||||
return new Thickness(System.Convert.ToDouble(value));
|
||||
}
|
||||
}
|
||||
return new Thickness(System.Convert.ToDouble(value));
|
||||
}
|
||||
return new Thickness(0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (parameter != null)
|
||||
{
|
||||
switch (parameter.ToString())
|
||||
{
|
||||
case "Left":
|
||||
return ((Thickness)value).Left;
|
||||
|
||||
case "Top":
|
||||
return ((Thickness)value).Top;
|
||||
|
||||
case "Right":
|
||||
return ((Thickness)value).Right;
|
||||
|
||||
case "Buttom":
|
||||
return ((Thickness)value).Bottom;
|
||||
|
||||
default:
|
||||
return ((Thickness)value).Left;
|
||||
}
|
||||
}
|
||||
return ((Thickness)value).Left;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class EnumDescriptionConverter : IValueConverter
|
||||
{
|
||||
#region constructor
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="EnumDescriptionConverter"/> class.
|
||||
/// </summary>
|
||||
public EnumDescriptionConverter()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IValueConverter
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
if (value is Enum)
|
||||
{
|
||||
return ((Enum)value).GetDescription();
|
||||
}
|
||||
else
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
37
AIStudio.Wpf.DiagramDesigner/Converters/ImageUrlConverter.cs
Normal file
37
AIStudio.Wpf.DiagramDesigner/Converters/ImageUrlConverter.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
[ValueConversion(typeof(string), typeof(ImageSource))]
|
||||
public class ImageUrlConverter : IValueConverter
|
||||
{
|
||||
static ImageUrlConverter()
|
||||
{
|
||||
Instance = new ImageUrlConverter();
|
||||
}
|
||||
|
||||
public static ImageUrlConverter Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
Uri imagePath = new Uri(value.ToString(), UriKind.RelativeOrAbsolute);
|
||||
ImageSource source = new BitmapImage(imagePath);
|
||||
return source;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class InvertBoolConverter : MarkupExtension, IValueConverter
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value for the target property of this markup extension.
|
||||
/// </summary>
|
||||
/// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
|
||||
/// <returns>Reference to the instance of this Int32IndexToNumberConverter.</returns>
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return !(bool)value;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return !(bool)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
AIStudio.Wpf.DiagramDesigner/Converters/LineDashConverter.cs
Normal file
24
AIStudio.Wpf.DiagramDesigner/Converters/LineDashConverter.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
|
||||
public class LineDashConverter : IValueConverter
|
||||
{
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
if (value is LineDashStyle arrowStyle)
|
||||
{
|
||||
return StrokeDashArray.Dash[(int)arrowStyle];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
/// <summary>
|
||||
/// 这是一个颠倒黑白的世界
|
||||
/// </summary>
|
||||
public sealed class TrueToFalseConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var v = (bool)value;
|
||||
return !v;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
22
AIStudio.Wpf.DiagramDesigner/Enums/ArrowPathStyle.cs
Normal file
22
AIStudio.Wpf.DiagramDesigner/Enums/ArrowPathStyle.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum ArrowPathStyle
|
||||
{
|
||||
None,
|
||||
Arrow1,
|
||||
Arrow2,
|
||||
Arrow3,
|
||||
Arrow4,
|
||||
Arrow5,
|
||||
Arrow6,
|
||||
Arrow7,
|
||||
Arrow8,
|
||||
Arrow9,
|
||||
Arrow10,
|
||||
Arrow11,
|
||||
}
|
||||
}
|
||||
24
AIStudio.Wpf.DiagramDesigner/Enums/ArrowSizeStyle.cs
Normal file
24
AIStudio.Wpf.DiagramDesigner/Enums/ArrowSizeStyle.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum ArrowSizeStyle
|
||||
{
|
||||
[Description("非常小")]
|
||||
VerySmall = 6,
|
||||
[Description("小")]
|
||||
Small = 8,
|
||||
[Description("中")]
|
||||
Middle = 10,
|
||||
[Description("大")]
|
||||
Large = 12,
|
||||
[Description("特别大")]
|
||||
ExtraLarge = 16,
|
||||
[Description("巨大")]
|
||||
Huge = 24,
|
||||
|
||||
}
|
||||
}
|
||||
18
AIStudio.Wpf.DiagramDesigner/Enums/BrushType.cs
Normal file
18
AIStudio.Wpf.DiagramDesigner/Enums/BrushType.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum BrushType
|
||||
{
|
||||
None,
|
||||
SolidColorBrush,
|
||||
LinearGradientBrush,
|
||||
RadialGradientBrush,
|
||||
ImageBrush,
|
||||
VisualBrush,
|
||||
DrawingBrush
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum CellHorizontalAlignment
|
||||
{
|
||||
None,
|
||||
Left,
|
||||
Center,
|
||||
Right
|
||||
}
|
||||
|
||||
public enum CellVerticalAlignment
|
||||
{
|
||||
None,
|
||||
Top,
|
||||
Center,
|
||||
Bottom
|
||||
}
|
||||
}
|
||||
15
AIStudio.Wpf.DiagramDesigner/Enums/ConnectorOrientation.cs
Normal file
15
AIStudio.Wpf.DiagramDesigner/Enums/ConnectorOrientation.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum ConnectorOrientation
|
||||
{
|
||||
None = 0,
|
||||
Left = 1,
|
||||
Top = 2,
|
||||
Right = 3,
|
||||
Bottom = 4
|
||||
}
|
||||
}
|
||||
13
AIStudio.Wpf.DiagramDesigner/Enums/CursorMode.cs
Normal file
13
AIStudio.Wpf.DiagramDesigner/Enums/CursorMode.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum CursorMode
|
||||
{
|
||||
Normal = 0,
|
||||
Format = 1,
|
||||
Move = 2,
|
||||
}
|
||||
}
|
||||
14
AIStudio.Wpf.DiagramDesigner/Enums/DiagramType.cs
Normal file
14
AIStudio.Wpf.DiagramDesigner/Enums/DiagramType.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum DiagramType
|
||||
{
|
||||
Normal,
|
||||
FlowChart,
|
||||
Logical,
|
||||
SFC,
|
||||
}
|
||||
}
|
||||
22
AIStudio.Wpf.DiagramDesigner/Enums/DrawMode.cs
Normal file
22
AIStudio.Wpf.DiagramDesigner/Enums/DrawMode.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum DrawMode
|
||||
{
|
||||
Normal = 0,
|
||||
Line = 1,
|
||||
Rectangle = 2,
|
||||
Ellipse = 3,
|
||||
Polyline = 4,
|
||||
Polygon = 5,
|
||||
DirectLine = 6,
|
||||
ConnectingLine = 10,
|
||||
CornerConnectingLine = 11,
|
||||
BoundaryConnectingLine = 12,
|
||||
RadiusConnectingLine = 13,
|
||||
Text = 20,
|
||||
}
|
||||
}
|
||||
14
AIStudio.Wpf.DiagramDesigner/Enums/FontCase.cs
Normal file
14
AIStudio.Wpf.DiagramDesigner/Enums/FontCase.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
|
||||
public enum FontCase
|
||||
{
|
||||
None,
|
||||
Upper,
|
||||
Lower,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum HorizontalVerticalAlignment
|
||||
{
|
||||
TopAlignLeft,
|
||||
TopAlignCenter,
|
||||
TopAlignRight,
|
||||
TopAlignJustify,
|
||||
CenterAlignLeft,
|
||||
CenterAlignCenter,
|
||||
CenterAlignRight,
|
||||
CenterAlignJustify,
|
||||
BottomAlignLeft,
|
||||
BottomAlignCenter,
|
||||
BottomAlignRight,
|
||||
BottomAlignJustify,
|
||||
}
|
||||
}
|
||||
32
AIStudio.Wpf.DiagramDesigner/Enums/LineDashStyle.cs
Normal file
32
AIStudio.Wpf.DiagramDesigner/Enums/LineDashStyle.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum LineDashStyle
|
||||
{
|
||||
None,
|
||||
Dash1,
|
||||
Dash2,
|
||||
Dash3,
|
||||
Dash4,
|
||||
Dash5,
|
||||
Dash6,
|
||||
Dash7,
|
||||
Dash8,
|
||||
Dash9,
|
||||
Dash10,
|
||||
Dash11,
|
||||
Dash12,
|
||||
Dash13,
|
||||
Dash14,
|
||||
Dash15,
|
||||
Dash16,
|
||||
Dash17,
|
||||
Dash18,
|
||||
Dash19,
|
||||
Dash20,
|
||||
Dash21
|
||||
}
|
||||
}
|
||||
27
AIStudio.Wpf.DiagramDesigner/Enums/LinearOrientation.cs
Normal file
27
AIStudio.Wpf.DiagramDesigner/Enums/LinearOrientation.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum LinearOrientation
|
||||
{
|
||||
[Description("左到右")]
|
||||
LeftToRight,
|
||||
[Description("左上到右下")]
|
||||
LeftTopToRightBottom,
|
||||
[Description("上到下")]
|
||||
TopToBottom,
|
||||
[Description("右上到左下")]
|
||||
RightTopToLeftBottom,
|
||||
[Description("右到左")]
|
||||
RightToLeft,
|
||||
[Description("右下到左上")]
|
||||
RightBottomToLeftTop,
|
||||
[Description("下到上")]
|
||||
BottomToTop,
|
||||
[Description("左下到右上")]
|
||||
LeftBottomToRightTop
|
||||
}
|
||||
}
|
||||
45
AIStudio.Wpf.DiagramDesigner/Enums/LockFlag.cs
Normal file
45
AIStudio.Wpf.DiagramDesigner/Enums/LockFlag.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum LockFlag
|
||||
{
|
||||
[Description("无锁定")]
|
||||
None,
|
||||
[Description("锁定所有")]
|
||||
All,
|
||||
[Description("宽度(敬请期待)")]
|
||||
Width,
|
||||
[Description("高度(敬请期待)")]
|
||||
Height,
|
||||
[Description("纵横比(敬请期待)")]
|
||||
Ratio,
|
||||
[Description("水平位置(敬请期待)")]
|
||||
Horizontal,
|
||||
[Description("垂直位置(敬请期待)")]
|
||||
Vertical,
|
||||
[Description("旋转(敬请期待)")]
|
||||
Rotate,
|
||||
[Description("起点(敬请期待)")]
|
||||
Start,
|
||||
[Description("终点(敬请期待)")]
|
||||
End,
|
||||
[Description("取消组合(敬请期待)")]
|
||||
UnGroup,
|
||||
[Description("编辑文本(敬请期待)")]
|
||||
Text,
|
||||
[Description("保护选中(敬请期待)")]
|
||||
IsSelected,
|
||||
[Description("保护删除(敬请期待)")]
|
||||
Delete,
|
||||
[Description("阻止连接(敬请期待)")]
|
||||
Link,
|
||||
[Description("格式(敬请期待)")]
|
||||
Format,
|
||||
[Description("保护主题(敬请期待)")]
|
||||
Theme,
|
||||
}
|
||||
}
|
||||
56
AIStudio.Wpf.DiagramDesigner/Enums/LogicalType.cs
Normal file
56
AIStudio.Wpf.DiagramDesigner/Enums/LogicalType.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum LogicalType
|
||||
{
|
||||
Input = -4,
|
||||
Output = -3,
|
||||
Constant = -2,
|
||||
Time = -1,
|
||||
None = 0,
|
||||
ADD = 1,
|
||||
SUB = 2,
|
||||
MUL = 3,
|
||||
DIV = 4,
|
||||
AVE = 5,
|
||||
MOD = 6,
|
||||
AND = 7,
|
||||
OR = 8,
|
||||
XOR = 9,
|
||||
NOT = 10,
|
||||
SHL = 11,//左移
|
||||
SHR = 12,//又移
|
||||
ROL = 13,//循环左移
|
||||
ROR = 14,//循环右移
|
||||
SEL = 15,//选择
|
||||
MAX = 16,
|
||||
MIN = 17,
|
||||
LIMIT = 18,//限幅
|
||||
GT = 19,//大于
|
||||
LT = 20,//小于
|
||||
GE = 21,//大于等于
|
||||
LE = 22,//小于等于
|
||||
EQ = 23,//等于
|
||||
NE = 24,//不等于
|
||||
ABS = 25,
|
||||
SQRT = 26,
|
||||
LN = 27,
|
||||
LOG = 28,
|
||||
EXP = 29,
|
||||
SIN = 30,
|
||||
COS = 31,
|
||||
TAN = 32,
|
||||
ASIN = 33,
|
||||
ACOS = 34,
|
||||
ATAN = 35,
|
||||
EXPT = 36,//幂
|
||||
Bool2Double = 37,
|
||||
Double2Bool = 38,
|
||||
BoolsToDouble = 39,
|
||||
DoubleToBools = 40,
|
||||
|
||||
}
|
||||
}
|
||||
15
AIStudio.Wpf.DiagramDesigner/Enums/PageSizeOrientation.cs
Normal file
15
AIStudio.Wpf.DiagramDesigner/Enums/PageSizeOrientation.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum PageSizeOrientation
|
||||
{
|
||||
[Description("竖向")]
|
||||
Vertical,
|
||||
[Description("横向")]
|
||||
Horizontal,
|
||||
}
|
||||
}
|
||||
74
AIStudio.Wpf.DiagramDesigner/Enums/PageSizeType.cs
Normal file
74
AIStudio.Wpf.DiagramDesigner/Enums/PageSizeType.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum PageSizeType
|
||||
{
|
||||
|
||||
[Description("Letter,8.5英寸*11英寸")]//612*792
|
||||
Letter,
|
||||
[Description("Folio,8.5英寸*13英寸")]//612*936
|
||||
Folio,
|
||||
[Description("Folio,8.5英寸*14英寸")]//612*1008
|
||||
Legal,
|
||||
[Description("Folio,7.25英寸*10.5英寸")]//522*756
|
||||
Executive,
|
||||
[Description("Folio,5.5英寸*8.5英寸")]//396*612
|
||||
Statement,
|
||||
[Description("#10 Envelope,4.125英寸*9.5英寸")]//297*684
|
||||
Envelope,
|
||||
[Description("Monarch Envelope,3.875英寸*7.5英寸")]//279*540
|
||||
MonarchEnvelope,
|
||||
[Description("Tabloid,11英寸*17英寸")]//792*1224
|
||||
Tabloid,
|
||||
[Description("Letter Small,8 1/2英寸*11英寸")]//612*792
|
||||
LetterSmall,
|
||||
[Description("C Sheet,17英寸*22英寸")]//1224*1584
|
||||
CSheet,
|
||||
[Description("D Sheet,22英寸*34英寸")]//1584*2448
|
||||
DSheet,
|
||||
[Description("E Sheet,34英寸*44英寸")]//2448*3168
|
||||
ESheet,
|
||||
[Description("A3 sheet,297毫米*420毫米")]//842*1191
|
||||
A3,
|
||||
[Description("A4 sheet,210毫米*297毫米")]//595*842
|
||||
A4,
|
||||
[Description("A5 sheet,148毫米*210毫米")]//420*595
|
||||
A5,
|
||||
[Description("B4 sheet,250毫米*354毫米")]//709*1003
|
||||
B4,
|
||||
[Description("B5 sheet,182毫米*257毫米")]//516*729
|
||||
B5,
|
||||
[Description("DL Envelope,110毫米*220毫米")]//312*624
|
||||
DLEnvelope,
|
||||
[Description("C5 Envelope,162毫米*229毫米")]//459*649
|
||||
C5Envelope,
|
||||
[Description("Quarto,215毫米*275毫米")]//609*780
|
||||
Quarto,
|
||||
[Description("C6 Quarto,114毫米*162毫米")]//323*459
|
||||
C6Quarto,
|
||||
[Description("B5 Quarto,176毫米*250毫米")]//499*709
|
||||
B5Quarto,
|
||||
[Description("Italy Quarto,110毫米*230毫米")]//312*652
|
||||
ItalyQuarto,
|
||||
[Description("A4 small sheet,210毫米*297毫米")]//595*842
|
||||
A4small,
|
||||
[Description("German Std Fanfold,8.5英寸*12英寸")]//612*864
|
||||
GermanStdFanfold,
|
||||
[Description("German Lagal Fanfold,8英寸*13英寸")]//576*936
|
||||
GermanLegalFanfold,
|
||||
[Description("PRC 16K,146毫米*215毫米")]//414*609
|
||||
PRC16K,
|
||||
[Description("PRC 32K,97毫米*151毫米")]//275*428
|
||||
PRC32K,
|
||||
//[Description("Japanese Postcard")]//283*420
|
||||
//JapanesePostcard,
|
||||
//[Description("Double Japanese Postcard")]//420*566
|
||||
//DoubleJapanesePostcard,
|
||||
[Description("自定义")]
|
||||
Custom,
|
||||
}
|
||||
}
|
||||
39
AIStudio.Wpf.DiagramDesigner/Enums/PageUnit.cs
Normal file
39
AIStudio.Wpf.DiagramDesigner/Enums/PageUnit.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum PageUnit
|
||||
{
|
||||
[Description("毫米(暂未实现)")]
|
||||
mm,
|
||||
[Description("厘米")]
|
||||
cm,
|
||||
[Description("米(暂未实现)")]
|
||||
m,
|
||||
[Description("千米(暂未实现)")]
|
||||
km,
|
||||
[Description("英寸")]
|
||||
inch,
|
||||
[Description("英尺和英寸(暂未实现)")]
|
||||
ftin,
|
||||
[Description("英尺(暂未实现)")]
|
||||
foot,
|
||||
[Description("码(暂未实现)")]
|
||||
yard,
|
||||
[Description("英里(暂未实现)")]
|
||||
mile,
|
||||
[Description("点(暂未实现)")]
|
||||
tiny,
|
||||
[Description("皮卡(暂未实现)")]
|
||||
pickup,
|
||||
[Description("迪多(暂未实现)")]
|
||||
ditto,
|
||||
[Description("西塞罗(暂未实现)")]
|
||||
cicero,
|
||||
[Description("像素(暂未实现)")]
|
||||
pixel,
|
||||
}
|
||||
}
|
||||
21
AIStudio.Wpf.DiagramDesigner/Enums/RadialOrientation.cs
Normal file
21
AIStudio.Wpf.DiagramDesigner/Enums/RadialOrientation.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum RadialOrientation
|
||||
{
|
||||
[Description("中心")]
|
||||
Center,
|
||||
[Description("左上")]
|
||||
LeftTop,
|
||||
[Description("右上")]
|
||||
RightTop,
|
||||
[Description("右下")]
|
||||
RightBottom,
|
||||
[Description("左下")]
|
||||
LeftBottom,
|
||||
}
|
||||
}
|
||||
13
AIStudio.Wpf.DiagramDesigner/Enums/ValueTypePoint.cs
Normal file
13
AIStudio.Wpf.DiagramDesigner/Enums/ValueTypePoint.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public enum ValueTypePoint
|
||||
{
|
||||
Real = 0,
|
||||
Int = 1,
|
||||
Bool = 2,
|
||||
}
|
||||
}
|
||||
626
AIStudio.Wpf.DiagramDesigner/Helpers/ColorHelper.cs
Normal file
626
AIStudio.Wpf.DiagramDesigner/Helpers/ColorHelper.cs
Normal file
@@ -0,0 +1,626 @@
|
||||
using System;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
/// <summary>
|
||||
/// 类 名:ColorHelper
|
||||
/// 功 能:提供从RGB到HSV/HSL色彩空间的相互转换
|
||||
/// 日 期:2015-02-08
|
||||
/// 修 改:2015-03-20
|
||||
/// 作 者:ls9512
|
||||
/// </summary>
|
||||
public static class ColorHelper
|
||||
{
|
||||
public static Color AdjustBrightness(Color c1, double factor)
|
||||
{
|
||||
|
||||
double r = ((c1.R * factor) > 255) ? 255 : (c1.R * factor);
|
||||
double g = ((c1.G * factor) > 255) ? 255 : (c1.G * factor);
|
||||
double b = ((c1.B * factor) > 255) ? 255 : (c1.B * factor);
|
||||
|
||||
Color c = Color.FromArgb(c1.A, (byte)r, (byte)g, (byte)b);
|
||||
return c;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGB转换HSV
|
||||
/// </summary>
|
||||
/// <param name="rgb"></param>
|
||||
/// <returns></returns>
|
||||
public static ColorHSV RgbToHsv(ColorRGB rgb)
|
||||
{
|
||||
float min, max, tmp, H, S, V;
|
||||
float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
|
||||
tmp = Math.Min(R, G);
|
||||
min = Math.Min(tmp, B);
|
||||
tmp = Math.Max(R, G);
|
||||
max = Math.Max(tmp, B);
|
||||
// H
|
||||
H = 0;
|
||||
if (max == min)
|
||||
{
|
||||
H = 0;
|
||||
}
|
||||
else if (max == R && G > B)
|
||||
{
|
||||
H = 60 * (G - B) * 1.0f / (max - min) + 0;
|
||||
}
|
||||
else if (max == R && G < B)
|
||||
{
|
||||
H = 60 * (G - B) * 1.0f / (max - min) + 360;
|
||||
}
|
||||
else if (max == G)
|
||||
{
|
||||
H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
|
||||
}
|
||||
else if (max == B)
|
||||
{
|
||||
H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
|
||||
}
|
||||
// S
|
||||
if (max == 0)
|
||||
{
|
||||
S = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
S = (max - min) * 1.0f / max;
|
||||
}
|
||||
// V
|
||||
V = max;
|
||||
return new ColorHSV((int)H, (int)(S * 255), (int)(V * 255));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HSV转换RGB
|
||||
/// </summary>
|
||||
/// <param name="hsv"></param>
|
||||
/// <returns></returns>
|
||||
public static ColorRGB HsvToRgb(ColorHSV hsv)
|
||||
{
|
||||
if (hsv.H == 360) hsv.H = 359; // 360为全黑,原因不明
|
||||
float R = 0f, G = 0f, B = 0f;
|
||||
if (hsv.S == 0)
|
||||
{
|
||||
return new ColorRGB(hsv.V, hsv.V, hsv.V);
|
||||
}
|
||||
float S = hsv.S * 1.0f / 255, V = hsv.V * 1.0f / 255;
|
||||
int H1 = (int)(hsv.H * 1.0f / 60), H = hsv.H;
|
||||
float F = H * 1.0f / 60 - H1;
|
||||
float P = V * (1.0f - S);
|
||||
float Q = V * (1.0f - F * S);
|
||||
float T = V * (1.0f - (1.0f - F) * S);
|
||||
switch (H1)
|
||||
{
|
||||
case 0: R = V; G = T; B = P; break;
|
||||
case 1: R = Q; G = V; B = P; break;
|
||||
case 2: R = P; G = V; B = T; break;
|
||||
case 3: R = P; G = Q; B = V; break;
|
||||
case 4: R = T; G = P; B = V; break;
|
||||
case 5: R = V; G = P; B = Q; break;
|
||||
}
|
||||
R = R * 255;
|
||||
G = G * 255;
|
||||
B = B * 255;
|
||||
while (R > 255) R -= 255;
|
||||
while (R < 0) R += 255;
|
||||
while (G > 255) G -= 255;
|
||||
while (G < 0) G += 255;
|
||||
while (B > 255) B -= 255;
|
||||
while (B < 0) B += 255;
|
||||
return new ColorRGB((int)R, (int)G, (int)B);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGB转换HSL
|
||||
/// </summary>
|
||||
/// <param name="rgb"></param>
|
||||
/// <returns></returns>
|
||||
public static ColorHSL RgbToHsl(ColorRGB rgb)
|
||||
{
|
||||
float min, max, tmp, H, S, L;
|
||||
float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
|
||||
tmp = Math.Min(R, G);
|
||||
min = Math.Min(tmp, B);
|
||||
tmp = Math.Max(R, G);
|
||||
max = Math.Max(tmp, B);
|
||||
// H
|
||||
H = 0;
|
||||
if (max == min)
|
||||
{
|
||||
H = 0; // 此时H应为未定义,通常写为0
|
||||
}
|
||||
else if (max == R && G > B)
|
||||
{
|
||||
H = 60 * (G - B) * 1.0f / (max - min) + 0;
|
||||
}
|
||||
else if (max == R && G < B)
|
||||
{
|
||||
H = 60 * (G - B) * 1.0f / (max - min) + 360;
|
||||
}
|
||||
else if (max == G)
|
||||
{
|
||||
H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
|
||||
}
|
||||
else if (max == B)
|
||||
{
|
||||
H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
|
||||
}
|
||||
// L
|
||||
L = 0.5f * (max + min);
|
||||
// S
|
||||
S = 0;
|
||||
if (L == 0 || max == min)
|
||||
{
|
||||
S = 0;
|
||||
}
|
||||
else if (0 < L && L < 0.5)
|
||||
{
|
||||
S = (max - min) / (L * 2);
|
||||
}
|
||||
else if (L > 0.5)
|
||||
{
|
||||
S = (max - min) / (2 - 2 * L);
|
||||
}
|
||||
return new ColorHSL((int)H, (int)(S * 255), (int)(L * 255));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HSL转换RGB
|
||||
/// </summary>
|
||||
/// <param name="hsl"></param>
|
||||
/// <returns></returns>
|
||||
public static ColorRGB HslToRgb(ColorHSL hsl)
|
||||
{
|
||||
float R = 0f, G = 0f, B = 0f;
|
||||
float S = hsl.S * 1.0f / 255, L = hsl.L * 1.0f / 255;
|
||||
float temp1, temp2, temp3;
|
||||
if (S == 0f) // 灰色
|
||||
{
|
||||
R = L;
|
||||
G = L;
|
||||
B = L;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (L < 0.5f)
|
||||
{
|
||||
temp2 = L * (1.0f + S);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp2 = L + S - L * S;
|
||||
}
|
||||
temp1 = 2.0f * L - temp2;
|
||||
float H = hsl.H * 1.0f / 360;
|
||||
// R
|
||||
temp3 = H + 1.0f / 3.0f;
|
||||
if (temp3 < 0) temp3 += 1.0f;
|
||||
if (temp3 > 1) temp3 -= 1.0f;
|
||||
R = temp3;
|
||||
// G
|
||||
temp3 = H;
|
||||
if (temp3 < 0) temp3 += 1.0f;
|
||||
if (temp3 > 1) temp3 -= 1.0f;
|
||||
G = temp3;
|
||||
// B
|
||||
temp3 = H - 1.0f / 3.0f;
|
||||
if (temp3 < 0) temp3 += 1.0f;
|
||||
if (temp3 > 1) temp3 -= 1.0f;
|
||||
B = temp3;
|
||||
}
|
||||
R = R * 255;
|
||||
G = G * 255;
|
||||
B = B * 255;
|
||||
return new ColorRGB((int)R, (int)G, (int)B);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGB转换HSV
|
||||
/// </summary>
|
||||
/// <param name="rgb"></param>
|
||||
/// <returns></returns>
|
||||
public static ColorHSV ColorToHsv(Color rgb)
|
||||
{
|
||||
float min, max, tmp, H, S, V;
|
||||
float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
|
||||
tmp = Math.Min(R, G);
|
||||
min = Math.Min(tmp, B);
|
||||
tmp = Math.Max(R, G);
|
||||
max = Math.Max(tmp, B);
|
||||
// H
|
||||
H = 0;
|
||||
if (max == min)
|
||||
{
|
||||
H = 0;
|
||||
}
|
||||
else if (max == R && G > B)
|
||||
{
|
||||
H = 60 * (G - B) * 1.0f / (max - min) + 0;
|
||||
}
|
||||
else if (max == R && G < B)
|
||||
{
|
||||
H = 60 * (G - B) * 1.0f / (max - min) + 360;
|
||||
}
|
||||
else if (max == G)
|
||||
{
|
||||
H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
|
||||
}
|
||||
else if (max == B)
|
||||
{
|
||||
H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
|
||||
}
|
||||
// S
|
||||
if (max == 0)
|
||||
{
|
||||
S = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
S = (max - min) * 1.0f / max;
|
||||
}
|
||||
// V
|
||||
V = max;
|
||||
return new ColorHSV((int)H, (int)(S * 255), (int)(V * 255));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HSV转换RGB
|
||||
/// </summary>
|
||||
/// <param name="hsv"></param>
|
||||
/// <returns></returns>
|
||||
public static Color HsvToColor(ColorHSV hsv)
|
||||
{
|
||||
if (hsv.H == 360) hsv.H = 359; // 360为全黑,原因不明
|
||||
float R = 0f, G = 0f, B = 0f;
|
||||
if (hsv.S == 0)
|
||||
{
|
||||
return Color.FromArgb(0xff, (byte)hsv.V, (byte)hsv.V, (byte)hsv.V);
|
||||
}
|
||||
float S = hsv.S * 1.0f / 255, V = hsv.V * 1.0f / 255;
|
||||
int H1 = (int)(hsv.H * 1.0f / 60), H = hsv.H;
|
||||
float F = H * 1.0f / 60 - H1;
|
||||
float P = V * (1.0f - S);
|
||||
float Q = V * (1.0f - F * S);
|
||||
float T = V * (1.0f - (1.0f - F) * S);
|
||||
switch (H1)
|
||||
{
|
||||
case 0: R = V; G = T; B = P; break;
|
||||
case 1: R = Q; G = V; B = P; break;
|
||||
case 2: R = P; G = V; B = T; break;
|
||||
case 3: R = P; G = Q; B = V; break;
|
||||
case 4: R = T; G = P; B = V; break;
|
||||
case 5: R = V; G = P; B = Q; break;
|
||||
}
|
||||
R = R * 255;
|
||||
G = G * 255;
|
||||
B = B * 255;
|
||||
while (R > 255) R -= 255;
|
||||
while (R < 0) R += 255;
|
||||
while (G > 255) G -= 255;
|
||||
while (G < 0) G += 255;
|
||||
while (B > 255) B -= 255;
|
||||
while (B < 0) B += 255;
|
||||
return Color.FromArgb(0xff, (byte)R, (byte)G, (byte)B);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RGB转换HSL
|
||||
/// </summary>
|
||||
/// <param name="rgb"></param>
|
||||
/// <returns></returns>
|
||||
public static ColorHSL ColorToHsl(Color rgb)
|
||||
{
|
||||
float min, max, tmp, H, S, L;
|
||||
float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
|
||||
tmp = Math.Min(R, G);
|
||||
min = Math.Min(tmp, B);
|
||||
tmp = Math.Max(R, G);
|
||||
max = Math.Max(tmp, B);
|
||||
// H
|
||||
H = 0;
|
||||
if (max == min)
|
||||
{
|
||||
H = 0; // 此时H应为未定义,通常写为0
|
||||
}
|
||||
else if (max == R && G > B)
|
||||
{
|
||||
H = 60 * (G - B) * 1.0f / (max - min) + 0;
|
||||
}
|
||||
else if (max == R && G < B)
|
||||
{
|
||||
H = 60 * (G - B) * 1.0f / (max - min) + 360;
|
||||
}
|
||||
else if (max == G)
|
||||
{
|
||||
H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
|
||||
}
|
||||
else if (max == B)
|
||||
{
|
||||
H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
|
||||
}
|
||||
// L
|
||||
L = 0.5f * (max + min);
|
||||
// S
|
||||
S = 0;
|
||||
if (L == 0 || max == min)
|
||||
{
|
||||
S = 0;
|
||||
}
|
||||
else if (0 < L && L < 0.5)
|
||||
{
|
||||
S = (max - min) / (L * 2);
|
||||
}
|
||||
else if (L > 0.5)
|
||||
{
|
||||
S = (max - min) / (2 - 2 * L);
|
||||
}
|
||||
return new ColorHSL((int)H, (int)(S * 255), (int)(L * 255));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HSL转换RGB
|
||||
/// </summary>
|
||||
/// <param name="hsl"></param>
|
||||
/// <returns></returns>
|
||||
public static Color HslToColor(ColorHSL hsl)
|
||||
{
|
||||
float R = 0f, G = 0f, B = 0f;
|
||||
float S = hsl.S * 1.0f / 255, L = hsl.L * 1.0f / 255;
|
||||
float temp1, temp2, temp3;
|
||||
if (S == 0f) // 灰色
|
||||
{
|
||||
R = L;
|
||||
G = L;
|
||||
B = L;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (L < 0.5f)
|
||||
{
|
||||
temp2 = L * (1.0f + S);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp2 = L + S - L * S;
|
||||
}
|
||||
temp1 = 2.0f * L - temp2;
|
||||
float H = hsl.H * 1.0f / 360;
|
||||
// R
|
||||
temp3 = H + 1.0f / 3.0f;
|
||||
if (temp3 < 0) temp3 += 1.0f;
|
||||
if (temp3 > 1) temp3 -= 1.0f;
|
||||
R = temp3;
|
||||
// G
|
||||
temp3 = H;
|
||||
if (temp3 < 0) temp3 += 1.0f;
|
||||
if (temp3 > 1) temp3 -= 1.0f;
|
||||
G = temp3;
|
||||
// B
|
||||
temp3 = H - 1.0f / 3.0f;
|
||||
if (temp3 < 0) temp3 += 1.0f;
|
||||
if (temp3 > 1) temp3 -= 1.0f;
|
||||
B = temp3;
|
||||
}
|
||||
R = R * 255;
|
||||
G = G * 255;
|
||||
B = B * 255;
|
||||
return Color.FromArgb(0xff, (byte)R, (byte)G, (byte)B);
|
||||
}
|
||||
}
|
||||
|
||||
#region RGB / HSV / HSL 颜色模型类
|
||||
/// <summary>
|
||||
/// 类 名:ColorHSL
|
||||
/// 功 能:H 色相 \ S 饱和度(纯度) \ L 亮度 颜色模型
|
||||
/// 日 期:2015-02-08
|
||||
/// 修 改:2015-03-20
|
||||
/// 作 者:ls9512
|
||||
/// </summary>
|
||||
public class ColorHSL
|
||||
{
|
||||
public ColorHSL(int h, int s, int l)
|
||||
{
|
||||
this._h = h;
|
||||
this._s = s;
|
||||
this._l = l;
|
||||
}
|
||||
|
||||
private int _h;
|
||||
private int _s;
|
||||
private int _l;
|
||||
|
||||
/// <summary>
|
||||
/// 色相
|
||||
/// </summary>
|
||||
public int H
|
||||
{
|
||||
get { return this._h; }
|
||||
set
|
||||
{
|
||||
this._h = value;
|
||||
this._h = this._h > 360 ? 360 : this._h;
|
||||
this._h = this._h < 0 ? 0 : this._h;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 饱和度(纯度)
|
||||
/// </summary>
|
||||
public int S
|
||||
{
|
||||
get { return this._s; }
|
||||
set
|
||||
{
|
||||
this._s = value;
|
||||
this._s = this._s > 255 ? 255 : this._s;
|
||||
this._s = this._s < 0 ? 0 : this._s;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 饱和度
|
||||
/// </summary>
|
||||
public int L
|
||||
{
|
||||
get { return this._l; }
|
||||
set
|
||||
{
|
||||
this._l = value;
|
||||
this._l = this._l > 255 ? 255 : this._l;
|
||||
this._l = this._l < 0 ? 0 : this._l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 类 名:ColorHSV
|
||||
/// 功 能:H 色相 \ S 饱和度(纯度) \ V 明度 颜色模型
|
||||
/// 日 期:2015-01-22
|
||||
/// 修 改:2015-03-20
|
||||
/// 作 者:ls9512
|
||||
/// </summary>
|
||||
public class ColorHSV
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造方法
|
||||
/// </summary>
|
||||
/// <param name="h"></param>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="v"></param>
|
||||
public ColorHSV(int h, int s, int v)
|
||||
{
|
||||
this._h = h;
|
||||
this._s = s;
|
||||
this._v = v;
|
||||
}
|
||||
|
||||
private int _h;
|
||||
private int _s;
|
||||
private int _v;
|
||||
|
||||
/// <summary>
|
||||
/// 色相
|
||||
/// </summary>
|
||||
public int H
|
||||
{
|
||||
get { return this._h; }
|
||||
set
|
||||
{
|
||||
this._h = value;
|
||||
this._h = this._h > 360 ? 360 : this._h;
|
||||
this._h = this._h < 0 ? 0 : this._h;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 饱和度(纯度)
|
||||
/// </summary>
|
||||
public int S
|
||||
{
|
||||
get { return this._s; }
|
||||
set
|
||||
{
|
||||
this._s = value;
|
||||
this._s = this._s > 255 ? 255 : this._s;
|
||||
this._s = this._s < 0 ? 0 : this._s;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 明度
|
||||
/// </summary>
|
||||
public int V
|
||||
{
|
||||
get { return this._v; }
|
||||
set
|
||||
{
|
||||
this._v = value;
|
||||
this._v = this._v > 255 ? 255 : this._v;
|
||||
this._v = this._v < 0 ? 0 : this._v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 类 名:ColorRGB
|
||||
/// 功 能:R 红色 \ G 绿色 \ B 蓝色 颜色模型
|
||||
/// 所有颜色模型的基类,RGB是用于输出到屏幕的颜色模式,所以所有模型都将转换成RGB输出
|
||||
/// 日 期:2015-01-22
|
||||
/// 修 改:2015-03-20
|
||||
/// 作 者:ls9512
|
||||
/// </summary>
|
||||
public class ColorRGB
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造方法
|
||||
/// </summary>
|
||||
/// <param name="r"></param>
|
||||
/// <param name="g"></param>
|
||||
/// <param name="b"></param>
|
||||
public ColorRGB(int r, int g, int b)
|
||||
{
|
||||
this._r = r;
|
||||
this._g = g;
|
||||
this._b = b;
|
||||
}
|
||||
|
||||
private int _r;
|
||||
private int _g;
|
||||
private int _b;
|
||||
|
||||
/// <summary>
|
||||
/// 红色
|
||||
/// </summary>
|
||||
public int R
|
||||
{
|
||||
get { return this._r; }
|
||||
set
|
||||
{
|
||||
this._r = value;
|
||||
this._r = this._r > 255 ? 255 : this._r;
|
||||
this._r = this._r < 0 ? 0 : this._r;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绿色
|
||||
/// </summary>
|
||||
public int G
|
||||
{
|
||||
get { return this._g; }
|
||||
set
|
||||
{
|
||||
this._g = value;
|
||||
this._g = this._g > 255 ? 255 : this._g;
|
||||
this._g = this._g < 0 ? 0 : this._g;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 蓝色
|
||||
/// </summary>
|
||||
public int B
|
||||
{
|
||||
get { return this._b; }
|
||||
set
|
||||
{
|
||||
this._b = value;
|
||||
this._b = this._b > 255 ? 255 : this._b;
|
||||
this._b = this._b < 0 ? 0 : this._b;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取实际颜色
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Color GetColor()
|
||||
{
|
||||
return Color.FromArgb(0xff, (byte)this._r, (byte)this._g, (byte)this._b);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
93
AIStudio.Wpf.DiagramDesigner/Helpers/ColorPickerManager.cs
Normal file
93
AIStudio.Wpf.DiagramDesigner/Helpers/ColorPickerManager.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取当前光标处颜色,win8下wpf测试成功
|
||||
/// </summary>
|
||||
public class ColorPickerManager
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="x">鼠标相对于显示器的坐标X</param>
|
||||
/// <param name="y">鼠标相对于显示器的坐标Y</param>
|
||||
/// <returns></returns>
|
||||
//public static System.Drawing.Color GetColor(int x, int y)
|
||||
//{
|
||||
// IntPtr hdc = GetDC(IntPtr.Zero);
|
||||
// uint pixel = GetPixel(hdc, x, y);
|
||||
// ReleaseDC(IntPtr.Zero, hdc);
|
||||
// System.Drawing.Color color = System.Drawing.Color.FromArgb((int)(pixel & 0x000000FF), (int)(pixel & 0x0000FF00) >> 8, (int)(pixel & 0x00FF0000) >> 16);
|
||||
|
||||
// return color;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="x">鼠标相对于显示器的坐标X</param>
|
||||
/// <param name="y">鼠标相对于显示器的坐标Y</param>
|
||||
/// <returns></returns>
|
||||
public static System.Windows.Media.Color GetColor(int x, int y)
|
||||
{
|
||||
IntPtr hdc = GetDC(IntPtr.Zero);
|
||||
uint pixel = GetPixel(hdc, x, y);
|
||||
ReleaseDC(IntPtr.Zero, hdc);
|
||||
System.Windows.Media.Color color = System.Windows.Media.Color.FromRgb((byte)(pixel & 0x000000FF), (byte)((pixel & 0x0000FF00) >> 8), (byte)((pixel & 0x00FF0000) >> 16));
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern bool BitBlt(
|
||||
IntPtr hdcDest, // 目标设备的句柄
|
||||
int nXDest, // 目标对象的左上角的X坐标
|
||||
int nYDest, // 目标对象的左上角的X坐标
|
||||
int nWidth, // 目标对象的矩形的宽度
|
||||
int nHeight, // 目标对象的矩形的长度
|
||||
IntPtr hdcSrc, // 源设备的句柄
|
||||
int nXSrc, // 源对象的左上角的X坐标
|
||||
int nYSrc, // 源对象的左上角的X坐标
|
||||
int dwRop // 光栅的操作值
|
||||
);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern IntPtr CreateDC(
|
||||
string lpszDriver, // 驱动名称
|
||||
string lpszDevice, // 设备名称
|
||||
string lpszOutput, // 无用,可以设定位"NULL"
|
||||
IntPtr lpInitData // 任意的打印机数据
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定窗口的设备场景
|
||||
/// </summary>
|
||||
/// <param name="hwnd">将获取其设备场景的窗口的句柄。若为0,则要获取整个屏幕的DC</param>
|
||||
/// <returns>指定窗口的设备场景句柄,出错则为0</returns>
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr GetDC(IntPtr hwnd);
|
||||
|
||||
/// <summary>
|
||||
/// 释放由调用GetDC函数获取的指定设备场景
|
||||
/// </summary>
|
||||
/// <param name="hwnd">要释放的设备场景相关的窗口句柄</param>
|
||||
/// <param name="hdc">要释放的设备场景句柄</param>
|
||||
/// <returns>执行成功为1,否则为0</returns>
|
||||
[DllImport("user32.dll")]
|
||||
private static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
|
||||
|
||||
/// <summary>
|
||||
/// 在指定的设备场景中取得一个像素的RGB值
|
||||
/// </summary>
|
||||
/// <param name="hdc">一个设备场景的句柄</param>
|
||||
/// <param name="nXPos">逻辑坐标中要检查的横坐标</param>
|
||||
/// <param name="nYPos">逻辑坐标中要检查的纵坐标</param>
|
||||
/// <returns>指定点的颜色</returns>
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);
|
||||
}
|
||||
}
|
||||
17
AIStudio.Wpf.DiagramDesigner/Helpers/ConnectorInfo.cs
Normal file
17
AIStudio.Wpf.DiagramDesigner/Helpers/ConnectorInfo.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public struct ConnectorInfo
|
||||
{
|
||||
public double DesignerItemLeft { get; set; }
|
||||
public double DesignerItemTop { get; set; }
|
||||
public Size DesignerItemSize { get; set; }
|
||||
public Point Position { get; set; }
|
||||
public ConnectorOrientation Orientation { get; set; }
|
||||
}
|
||||
}
|
||||
406
AIStudio.Wpf.DiagramDesigner/Helpers/ControlExtession.cs
Normal file
406
AIStudio.Wpf.DiagramDesigner/Helpers/ControlExtession.cs
Normal file
@@ -0,0 +1,406 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public static class ControlExtession
|
||||
{
|
||||
#region TreeView操作扩展方法
|
||||
//code:http://www.codeproject.com/Articles/36193/WPF-TreeView-tools
|
||||
|
||||
/// <summary>
|
||||
/// Returns the TreeViewItem of a data bound object.
|
||||
/// </summary>
|
||||
/// <param name="treeView">TreeView</param>
|
||||
/// <param name="obj">Data bound object</param>
|
||||
/// <returns>The TreeViewItem of the data bound object or null.</returns>
|
||||
public static TreeViewItem GetItemFromObject(this TreeView treeView, object obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
DependencyObject dObject = GetContainerFormObject(treeView, obj);
|
||||
TreeViewItem tvi = dObject as TreeViewItem;
|
||||
while (tvi == null)
|
||||
{
|
||||
dObject = VisualTreeHelper.GetParent(dObject);
|
||||
tvi = dObject as TreeViewItem;
|
||||
}
|
||||
return tvi;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static DependencyObject GetContainerFormObject(ItemsControl item, object obj)
|
||||
{
|
||||
if (item == null)
|
||||
return null;
|
||||
|
||||
DependencyObject dObject = null;
|
||||
dObject = item.ItemContainerGenerator.ContainerFromItem(obj);
|
||||
|
||||
if (dObject != null)
|
||||
return dObject;
|
||||
|
||||
var query = from childItem in item.Items.Cast<object>()
|
||||
let childControl = item.ItemContainerGenerator.ContainerFromItem(childItem) as ItemsControl
|
||||
select GetContainerFormObject(childControl, obj);
|
||||
|
||||
return query.FirstOrDefault(i => i != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects a data bound object of a TreeView.
|
||||
/// </summary>
|
||||
/// <param name="treeView">TreeView</param>
|
||||
/// <param name="obj">Data bound object</param>
|
||||
public static void SelectObject(this TreeView treeView, object obj)
|
||||
{
|
||||
treeView.SelectObject(obj, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Selects or deselects a data bound object of a TreeView.
|
||||
/// </summary>
|
||||
/// <param name="treeView">TreeView</param>
|
||||
/// <param name="obj">Data bound object</param>
|
||||
/// <param name="selected">select or deselect</param>
|
||||
public static void SelectObject(this TreeView treeView, object obj, bool selected)
|
||||
{
|
||||
var tvi = treeView.GetItemFromObject(obj);
|
||||
if (tvi != null)
|
||||
{
|
||||
tvi.IsSelected = selected;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a data bound object of a TreeView is selected.
|
||||
/// </summary>
|
||||
/// <param name="treeView">TreeView</param>
|
||||
/// <param name="obj">Data bound object</param>
|
||||
/// <returns>Returns true if the object is selected, and false if it is not selected or obj is not in the tree.</returns>
|
||||
public static bool IsObjectSelected(this TreeView treeView, object obj)
|
||||
{
|
||||
var tvi = treeView.GetItemFromObject(obj);
|
||||
if (tvi != null)
|
||||
{
|
||||
return tvi.IsSelected;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a data bound object of a TreeView is focused.
|
||||
/// </summary>
|
||||
/// <param name="treeView">TreeView</param>
|
||||
/// <param name="obj">Data bound object</param>
|
||||
/// <returns>Returns true if the object is focused, and false if it is not focused or obj is not in the tree.</returns>
|
||||
public static bool IsObjectFocused(this TreeView treeView, object obj)
|
||||
{
|
||||
var tvi = treeView.GetItemFromObject(obj);
|
||||
if (tvi != null)
|
||||
{
|
||||
return tvi.IsFocused;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands a data bound object of a TreeView.
|
||||
/// </summary>
|
||||
/// <param name="treeView">TreeView</param>
|
||||
/// <param name="obj">Data bound object</param>
|
||||
public static void ExpandObject(this TreeView treeView, object obj)
|
||||
{
|
||||
treeView.ExpandObject(obj, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expands or collapses a data bound object of a TreeView.
|
||||
/// </summary>
|
||||
/// <param name="treeView">TreeView</param>
|
||||
/// <param name="obj">Data bound object</param>
|
||||
/// <param name="expanded">expand or collapse</param>
|
||||
public static void ExpandObject(this TreeView treeView, object obj, bool expanded)
|
||||
{
|
||||
var tvi = treeView.GetItemFromObject(obj);
|
||||
if (tvi != null)
|
||||
{
|
||||
tvi.IsExpanded = expanded;
|
||||
if (expanded)
|
||||
{
|
||||
// update layout, so that following calls to f.e. SelectObject on child nodes will
|
||||
// find theire TreeViewNodes
|
||||
treeView.UpdateLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns if a douta bound object of a TreeView is expanded.
|
||||
/// </summary>
|
||||
/// <param name="treeView">TreeView</param>
|
||||
/// <param name="obj">Data bound object</param>
|
||||
/// <returns>Returns true if the object is expanded, and false if it is collapsed or obj is not in the tree.</returns>
|
||||
public static bool IsObjectExpanded(this TreeView treeView, object obj)
|
||||
{
|
||||
var tvi = treeView.GetItemFromObject(obj);
|
||||
if (tvi != null)
|
||||
{
|
||||
return tvi.IsExpanded;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retuns the parent TreeViewItem.
|
||||
/// </summary>
|
||||
/// <param name="item">TreeViewItem</param>
|
||||
/// <returns>Parent TreeViewItem</returns>
|
||||
public static TreeViewItem GetParentItem(this TreeViewItem item)
|
||||
{
|
||||
var dObject = VisualTreeHelper.GetParent(item);
|
||||
TreeViewItem tvi = dObject as TreeViewItem;
|
||||
while (tvi == null)
|
||||
{
|
||||
dObject = VisualTreeHelper.GetParent(dObject);
|
||||
tvi = dObject as TreeViewItem;
|
||||
}
|
||||
return tvi;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FindParent/FindChildren
|
||||
/// <summary>
|
||||
/// Finds a parent of a given item on the visual tree.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the queried item.</typeparam>
|
||||
/// <param name="child">A direct or indirect child of the
|
||||
/// queried item.</param>
|
||||
/// <returns>The first parent item that matches the submitted
|
||||
/// type parameter. If not matching item can be found, a null
|
||||
/// reference is being returned.</returns>
|
||||
public static T TryFindParent<T>(this DependencyObject child)
|
||||
where T : DependencyObject
|
||||
{
|
||||
//get parent item
|
||||
DependencyObject parentObject = GetParentObject(child);
|
||||
|
||||
//we've reached the end of the tree
|
||||
if (parentObject == null) return null;
|
||||
|
||||
//check if the parent matches the type we're looking for
|
||||
T parent = parentObject as T;
|
||||
return parent ?? TryFindParent<T>(parentObject);
|
||||
}
|
||||
|
||||
//public static T FindParent<T>(DependencyObject child) where T : DependencyObject
|
||||
//{
|
||||
// //get parent item
|
||||
// var parentObject = VisualTreeHelper.GetParent(child);
|
||||
|
||||
// //we've reached the end of the tree
|
||||
// if (parentObject == null) return null;
|
||||
|
||||
// //check if the parent matches the type we're looking for
|
||||
// var parent = parentObject as T;
|
||||
// return parent ?? FindParent<T>(parentObject);
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Finds a Child of a given item in the visual tree.
|
||||
/// </summary>
|
||||
/// <param name="parent">A direct parent of the queried item.</param>
|
||||
/// <typeparam name="T">The type of the queried item.</typeparam>
|
||||
/// <param name="childName">x:Name or Name of child. </param>
|
||||
/// <returns>The first parent item that matches the submitted type parameter.
|
||||
/// If not matching item can be found,
|
||||
/// a null parent is being returned.</returns>
|
||||
public static T FindChild<T>(this DependencyObject parent, string childName)
|
||||
where T : DependencyObject
|
||||
{
|
||||
// Confirm parent and childName are valid.
|
||||
if (parent == null) return null;
|
||||
|
||||
T foundChild = null;
|
||||
|
||||
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
|
||||
for (int i = 0; i < childrenCount; i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(parent, i);
|
||||
// If the child is not of the request child type child
|
||||
T childType = child as T;
|
||||
if (childType == null)
|
||||
{
|
||||
// recursively drill down the tree
|
||||
foundChild = FindChild<T>(child, childName);
|
||||
|
||||
// If the child is found, break so we do not overwrite the found child.
|
||||
if (foundChild != null) break;
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(childName))
|
||||
{
|
||||
var frameworkElement = child as FrameworkElement;
|
||||
// If the child's name is set for search
|
||||
if (frameworkElement != null && frameworkElement.Name == childName)
|
||||
{
|
||||
// if the child's name is of the request name
|
||||
foundChild = (T)child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// child element found.
|
||||
foundChild = (T)child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return foundChild;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is an alternative to WPF's
|
||||
/// <see cref="VisualTreeHelper.GetParent"/> method, which also
|
||||
/// supports content elements. Keep in mind that for content element,
|
||||
/// this method falls back to the logical tree of the element!
|
||||
/// </summary>
|
||||
/// <param name="child">The item to be processed.</param>
|
||||
/// <returns>The submitted item's parent, if available. Otherwise
|
||||
/// null.</returns>
|
||||
public static DependencyObject GetParentObject(this DependencyObject child)
|
||||
{
|
||||
if (child == null) return null;
|
||||
|
||||
//handle content elements separately
|
||||
var contentElement = child as ContentElement;
|
||||
if (contentElement != null)
|
||||
{
|
||||
DependencyObject parent = ContentOperations.GetParent(contentElement);
|
||||
if (parent != null) return parent;
|
||||
|
||||
var fce = contentElement as FrameworkContentElement;
|
||||
return fce != null ? fce.Parent : null;
|
||||
}
|
||||
|
||||
//also try searching for parent in framework elements (such as DockPanel, etc)
|
||||
var frameworkElement = child as FrameworkElement;
|
||||
if (frameworkElement != null)
|
||||
{
|
||||
DependencyObject parent = frameworkElement.Parent;
|
||||
if (parent != null) return parent;
|
||||
}
|
||||
|
||||
//if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
|
||||
return VisualTreeHelper.GetParent(child);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analyzes both visual and logical tree in order to find all elements of a given
|
||||
/// type that are descendants of the <paramref name="source"/> item.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the queried items.</typeparam>
|
||||
/// <param name="source">The root element that marks the source of the search. If the
|
||||
/// source is already of the requested type, it will not be included in the result.</param>
|
||||
/// <param name="forceUsingTheVisualTreeHelper">Sometimes it's better to search in the VisualTree (e.g. in tests)</param>
|
||||
/// <returns>All descendants of <paramref name="source"/> that match the requested type.</returns>
|
||||
public static IEnumerable<T> FindChildren<T>(this DependencyObject source, bool forceUsingTheVisualTreeHelper = false) where T : DependencyObject
|
||||
{
|
||||
if (source != null)
|
||||
{
|
||||
var childs = GetChildObjects(source, forceUsingTheVisualTreeHelper);
|
||||
foreach (DependencyObject child in childs)
|
||||
{
|
||||
//analyze if children match the requested type
|
||||
if (child != null && child is T)
|
||||
{
|
||||
yield return (T)child;
|
||||
}
|
||||
|
||||
//recurse tree
|
||||
foreach (T descendant in FindChildren<T>(child))
|
||||
{
|
||||
yield return descendant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is an alternative to WPF's
|
||||
/// <see cref="VisualTreeHelper.GetChild"/> method, which also
|
||||
/// supports content elements. Keep in mind that for content elements,
|
||||
/// this method falls back to the logical tree of the element.
|
||||
/// </summary>
|
||||
/// <param name="parent">The item to be processed.</param>
|
||||
/// <param name="forceUsingTheVisualTreeHelper">Sometimes it's better to search in the VisualTree (e.g. in tests)</param>
|
||||
/// <returns>The submitted item's child elements, if available.</returns>
|
||||
public static IEnumerable<DependencyObject> GetChildObjects(this DependencyObject parent, bool forceUsingTheVisualTreeHelper = false)
|
||||
{
|
||||
if (parent == null) yield break;
|
||||
|
||||
if (!forceUsingTheVisualTreeHelper && (parent is ContentElement || parent is FrameworkElement))
|
||||
{
|
||||
//use the logical tree for content / framework elements
|
||||
foreach (object obj in LogicalTreeHelper.GetChildren(parent))
|
||||
{
|
||||
var depObj = obj as DependencyObject;
|
||||
if (depObj != null) yield return (DependencyObject)obj;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//use the visual tree per default
|
||||
int count = VisualTreeHelper.GetChildrenCount(parent);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
yield return VisualTreeHelper.GetChild(parent, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to locate a given item within the visual tree,
|
||||
/// starting with the dependency object at a given position.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the element to be found
|
||||
/// on the visual tree of the element at the given location.</typeparam>
|
||||
/// <param name="reference">The main element which is used to perform
|
||||
/// hit testing.</param>
|
||||
/// <param name="point">The position to be evaluated on the origin.</param>
|
||||
public static T TryFindFromPoint<T>(UIElement reference, Point point)
|
||||
where T : DependencyObject
|
||||
{
|
||||
var element = reference.InputHitTest(point) as DependencyObject;
|
||||
|
||||
if (element == null)
|
||||
return null;
|
||||
if (element is T)
|
||||
return (T)element;
|
||||
return TryFindParent<T>(element);
|
||||
|
||||
//DependencyObject hitObject = reference.InputHitTest(point) as DependencyObject;
|
||||
//while (hitObject != null &&
|
||||
// hitObject.GetType() != typeof(DesignerCanvas))
|
||||
//{
|
||||
// if (hitObject is T)
|
||||
// {
|
||||
// return (T)hitObject;
|
||||
// }
|
||||
// hitObject = VisualTreeHelper.GetParent(hitObject);
|
||||
//}
|
||||
|
||||
//return null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ControlMouseDoubleClickCommandBehavior : Behavior<FrameworkElement>
|
||||
{
|
||||
#region Overrides
|
||||
protected override void OnAttached()
|
||||
{
|
||||
|
||||
base.OnAttached();
|
||||
AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
|
||||
EnableDisableElement();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
//Get the ItemsControl and then get the item, and check there
|
||||
//is an actual item, as if we are using a ListView we may have clicked the
|
||||
//headers which are not items
|
||||
//ItemsControl listView = sender as ItemsControl;
|
||||
//DependencyObject originalSender = e.OriginalSource as DependencyObject;
|
||||
//if (listView == null || originalSender == null) return;
|
||||
|
||||
//DependencyObject container =
|
||||
// ItemsControl.ContainerFromElement
|
||||
// (sender as ItemsControl, e.OriginalSource as DependencyObject);
|
||||
|
||||
//if (container == null ||
|
||||
// container == DependencyProperty.UnsetValue) return;
|
||||
|
||||
//// found a container, now find the item.
|
||||
//object activatedItem =
|
||||
// listView.ItemContainerGenerator.ItemFromContainer(container);
|
||||
|
||||
//if (activatedItem != null)
|
||||
//{
|
||||
// Invoke(activatedItem, e);
|
||||
//}
|
||||
|
||||
FrameworkElement control = sender as FrameworkElement;
|
||||
DependencyObject originalSender = e.OriginalSource as DependencyObject;
|
||||
if (control == null || originalSender == null) return;
|
||||
|
||||
if (e.ClickCount >= 2)
|
||||
{
|
||||
Invoke(control, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnCommandChanged(ControlMouseDoubleClickCommandBehavior thisBehaviour,
|
||||
DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (thisBehaviour == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OldValue != null)
|
||||
{
|
||||
((ICommand)e.OldValue).CanExecuteChanged -= thisBehaviour.OnCommandCanExecuteChanged;
|
||||
}
|
||||
|
||||
ICommand command = (ICommand)e.NewValue;
|
||||
|
||||
if (command != null)
|
||||
{
|
||||
command.CanExecuteChanged += thisBehaviour.OnCommandCanExecuteChanged;
|
||||
}
|
||||
|
||||
thisBehaviour.EnableDisableElement();
|
||||
}
|
||||
|
||||
private bool IsAssociatedElementDisabled()
|
||||
{
|
||||
return AssociatedObject != null && !AssociatedObject.IsEnabled;
|
||||
}
|
||||
|
||||
private void EnableDisableElement()
|
||||
{
|
||||
if (AssociatedObject == null || Command == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssociatedObject.IsEnabled = Command.CanExecute(this.CommandParameter);
|
||||
}
|
||||
|
||||
private void OnCommandCanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
EnableDisableElement();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
/// <param name="parameter">The EventArgs of the fired event.</param>
|
||||
protected void Invoke(object clickedItem, MouseButtonEventArgs parameter)
|
||||
{
|
||||
if (IsAssociatedElementDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ICommand command = Command;
|
||||
if (command != null && command.CanExecute(CommandParameter))
|
||||
{
|
||||
command.Execute(new EventToCommandArgs(clickedItem, command,
|
||||
CommandParameter, (EventArgs)parameter));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DPs
|
||||
|
||||
#region CommandParameter
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="CommandParameter" /> dependency property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
|
||||
"CommandParameter", typeof(object), typeof(ControlMouseDoubleClickCommandBehavior),
|
||||
new PropertyMetadata(null,
|
||||
(s, e) =>
|
||||
{
|
||||
ControlMouseDoubleClickCommandBehavior sender = s as ControlMouseDoubleClickCommandBehavior;
|
||||
if (sender == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender.AssociatedObject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sender.EnableDisableElement();
|
||||
}));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an object that will be passed to the <see cref="Command" />
|
||||
/// attached to this trigger. This is a DependencyProperty.
|
||||
/// </summary>
|
||||
public object CommandParameter
|
||||
{
|
||||
get { return (Object)GetValue(CommandParameterProperty); }
|
||||
set { SetValue(CommandParameterProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Command
|
||||
/// <summary
|
||||
/// >
|
||||
/// Identifies the <see cref="Command" /> dependency property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
|
||||
"Command", typeof(ICommand), typeof(ControlMouseDoubleClickCommandBehavior),
|
||||
new PropertyMetadata(null,
|
||||
(s, e) => OnCommandChanged(s as ControlMouseDoubleClickCommandBehavior, e)));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ICommand that this trigger is bound to. This
|
||||
/// is a DependencyProperty.
|
||||
/// </summary>
|
||||
public ICommand Command
|
||||
{
|
||||
get { return (ICommand)GetValue(CommandProperty); }
|
||||
set { SetValue(CommandProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
using Microsoft.Xaml.Behaviors;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ControlMouseLeftButtonDownCommandBehavior : Behavior<FrameworkElement>
|
||||
{
|
||||
#region Overrides
|
||||
protected override void OnAttached()
|
||||
{
|
||||
|
||||
base.OnAttached();
|
||||
AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;
|
||||
EnableDisableElement();
|
||||
}
|
||||
|
||||
protected override void OnDetaching()
|
||||
{
|
||||
AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObject_PreviewMouseLeftButtonDown;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
//Get the ItemsControl and then get the item, and check there
|
||||
//is an actual item, as if we are using a ListView we may have clicked the
|
||||
//headers which are not items
|
||||
//ItemsControl listView = sender as ItemsControl;
|
||||
//DependencyObject originalSender = e.OriginalSource as DependencyObject;
|
||||
//if (listView == null || originalSender == null) return;
|
||||
|
||||
//DependencyObject container =
|
||||
// ItemsControl.ContainerFromElement
|
||||
// (sender as ItemsControl, e.OriginalSource as DependencyObject);
|
||||
|
||||
//if (container == null ||
|
||||
// container == DependencyProperty.UnsetValue) return;
|
||||
|
||||
//// found a container, now find the item.
|
||||
//object activatedItem =
|
||||
// listView.ItemContainerGenerator.ItemFromContainer(container);
|
||||
|
||||
//if (activatedItem != null)
|
||||
//{
|
||||
// Invoke(activatedItem, e);
|
||||
//}
|
||||
|
||||
FrameworkElement control = sender as FrameworkElement;
|
||||
DependencyObject originalSender = e.OriginalSource as DependencyObject;
|
||||
if (control == null || originalSender == null) return;
|
||||
|
||||
Invoke(control, e);
|
||||
}
|
||||
|
||||
private static void OnCommandChanged(ControlMouseLeftButtonDownCommandBehavior thisBehaviour,
|
||||
DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (thisBehaviour == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.OldValue != null)
|
||||
{
|
||||
((ICommand)e.OldValue).CanExecuteChanged -= thisBehaviour.OnCommandCanExecuteChanged;
|
||||
}
|
||||
|
||||
ICommand command = (ICommand)e.NewValue;
|
||||
|
||||
if (command != null)
|
||||
{
|
||||
command.CanExecuteChanged += thisBehaviour.OnCommandCanExecuteChanged;
|
||||
}
|
||||
|
||||
thisBehaviour.EnableDisableElement();
|
||||
}
|
||||
|
||||
private bool IsAssociatedElementDisabled()
|
||||
{
|
||||
return AssociatedObject != null && !AssociatedObject.IsEnabled;
|
||||
}
|
||||
|
||||
private void EnableDisableElement()
|
||||
{
|
||||
if (AssociatedObject == null || Command == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssociatedObject.IsEnabled = Command.CanExecute(this.CommandParameter);
|
||||
}
|
||||
|
||||
private void OnCommandCanExecuteChanged(object sender, EventArgs e)
|
||||
{
|
||||
EnableDisableElement();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
/// <param name="parameter">The EventArgs of the fired event.</param>
|
||||
protected void Invoke(object clickedItem, MouseButtonEventArgs parameter)
|
||||
{
|
||||
if (IsAssociatedElementDisabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ICommand command = Command;
|
||||
if (command != null && command.CanExecute(CommandParameter))
|
||||
{
|
||||
command.Execute(new EventToCommandArgs(clickedItem, command,
|
||||
CommandParameter, (EventArgs)parameter));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DPs
|
||||
|
||||
#region CommandParameter
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="CommandParameter" /> dependency property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
|
||||
"CommandParameter", typeof(object), typeof(ControlMouseLeftButtonDownCommandBehavior),
|
||||
new PropertyMetadata(null,
|
||||
(s, e) =>
|
||||
{
|
||||
ControlMouseLeftButtonDownCommandBehavior sender = s as ControlMouseLeftButtonDownCommandBehavior;
|
||||
if (sender == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (sender.AssociatedObject == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
sender.EnableDisableElement();
|
||||
}));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an object that will be passed to the <see cref="Command" />
|
||||
/// attached to this trigger. This is a DependencyProperty.
|
||||
/// </summary>
|
||||
public object CommandParameter
|
||||
{
|
||||
get { return (Object)GetValue(CommandParameterProperty); }
|
||||
set { SetValue(CommandParameterProperty, value); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Command
|
||||
/// <summary
|
||||
/// >
|
||||
/// Identifies the <see cref="Command" /> dependency property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
|
||||
"Command", typeof(ICommand), typeof(ControlMouseLeftButtonDownCommandBehavior),
|
||||
new PropertyMetadata(null,
|
||||
(s, e) => OnCommandChanged(s as ControlMouseLeftButtonDownCommandBehavior, e)));
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the ICommand that this trigger is bound to. This
|
||||
/// is a DependencyProperty.
|
||||
/// </summary>
|
||||
public ICommand Command
|
||||
{
|
||||
get { return (ICommand)GetValue(CommandProperty); }
|
||||
set { SetValue(CommandProperty, value); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
182
AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs
Normal file
182
AIStudio.Wpf.DiagramDesigner/Helpers/CopyHelper.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class CopyHelper
|
||||
{
|
||||
public static T DeepCopyByReflect<T>(T obj)
|
||||
{
|
||||
//如果是字符串或值类型则直接返回
|
||||
if (obj == null || obj is string || obj.GetType().IsValueType) return obj;
|
||||
|
||||
object retval = Activator.CreateInstance(obj.GetType());
|
||||
FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
|
||||
foreach (FieldInfo field in fields)
|
||||
{
|
||||
try { field.SetValue(retval, DeepCopyByReflect(field.GetValue(obj))); }
|
||||
catch { }
|
||||
}
|
||||
return (T)retval;
|
||||
}
|
||||
|
||||
public static TChild AutoCopy<TParent, TChild>(TParent parent) where TChild : TParent, new()
|
||||
{
|
||||
TChild child = new TChild();
|
||||
var ParentType = typeof(TParent);
|
||||
var Properties = ParentType.GetProperties();
|
||||
foreach (var Propertie in Properties)
|
||||
{
|
||||
//循环遍历属性
|
||||
if (Propertie.CanRead && Propertie.CanWrite)
|
||||
{
|
||||
//进行属性拷贝
|
||||
Propertie.SetValue(child, Propertie.GetValue(parent, null), null);
|
||||
}
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
public static T AutoCopy<T>(T source) where T : new()
|
||||
{
|
||||
//如果是字符串或值类型则直接返回
|
||||
if (source == null || source is string || source.GetType().IsValueType) return source;
|
||||
|
||||
T target = new T();
|
||||
var Properties = typeof(T).GetProperties();
|
||||
foreach (var Propertie in Properties)
|
||||
{
|
||||
//循环遍历属性
|
||||
if (Propertie.CanRead && Propertie.CanWrite)
|
||||
{
|
||||
//进行属性拷贝
|
||||
Propertie.SetValue(target, Propertie.GetValue(source, null), null);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
public static T DeepCopy<T>(T obj)
|
||||
{
|
||||
//如果是字符串或值类型则直接返回
|
||||
if (obj == null || obj is string || obj.GetType().IsValueType) return obj;
|
||||
|
||||
object retval;
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
XmlSerializer xml = new XmlSerializer(typeof(T));
|
||||
xml.Serialize(ms, obj);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
retval = xml.Deserialize(ms);
|
||||
ms.Close();
|
||||
}
|
||||
return (T)retval;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反射实现两个类的对象之间相同属性的值的复制
|
||||
/// 适用于初始化新实体
|
||||
/// </summary>
|
||||
/// <typeparam name="D">返回的实体</typeparam>
|
||||
/// <typeparam name="S">数据源实体</typeparam>
|
||||
/// <param name="s">数据源实体</param>
|
||||
/// <returns>返回的新实体</returns>
|
||||
public static D Mapper<D, S>(S s)
|
||||
{
|
||||
D d = Activator.CreateInstance<D>(); //构造新实例
|
||||
try
|
||||
{
|
||||
var Types = s.GetType();//获得类型
|
||||
var Typed = typeof(D);
|
||||
foreach (PropertyInfo sp in Types.GetProperties().Where(p => p.CanRead))//获得类型的属性字段
|
||||
{
|
||||
foreach (PropertyInfo dp in Typed.GetProperties().Where(p => p.CanWrite))
|
||||
{
|
||||
if (dp.Name == sp.Name && dp.PropertyType == sp.PropertyType)//判断属性名是否相同
|
||||
{
|
||||
dp.SetValue(d, sp.GetValue(s, null), null);//获得s对象属性的值复制给d对象的属性
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public static void CopyPropertyValue(object s, object d, string propertyName = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var Types = s.GetType();//获得类型
|
||||
var Typed = d.GetType();
|
||||
var sps = Types.GetProperties().Where(p => p.CanRead && (string.IsNullOrEmpty(propertyName) || p.Name == propertyName));//获得类型的属性字段
|
||||
var dps = Typed.GetProperties().Where(p => p.CanWrite && (string.IsNullOrEmpty(propertyName) || p.Name == propertyName));
|
||||
|
||||
foreach (PropertyInfo sp in sps)//获得类型的属性字段
|
||||
{
|
||||
foreach (PropertyInfo dp in dps)
|
||||
{
|
||||
if (dp.Name == sp.Name && dp.PropertyType == sp.PropertyType)//判断属性名是否相同
|
||||
{
|
||||
dp.SetValue(d, sp.GetValue(s, null), null);//获得s对象属性的值复制给d对象的属性
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public static ColorViewModel Mapper(IColorViewModel s)
|
||||
{
|
||||
var d = CopyHelper.Mapper<ColorViewModel, IColorViewModel>(s);
|
||||
d.LineColor = CopyHelper.Mapper<ColorObject, IColorObject>(s.LineColor);
|
||||
d.FillColor = CopyHelper.Mapper<ColorObject, IColorObject>(s.FillColor);
|
||||
d.LineColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.LineColor.GradientStop);
|
||||
d.FillColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.FillColor.GradientStop);
|
||||
return d;
|
||||
}
|
||||
|
||||
public static T Mapper<T>(IColorViewModel s) where T: IColorViewModel
|
||||
{
|
||||
var d = CopyHelper.Mapper<T, IColorViewModel>(s);
|
||||
d.LineColor = CopyHelper.Mapper<ColorObjectItem, IColorObject>(s.LineColor);
|
||||
d.FillColor = CopyHelper.Mapper<ColorObjectItem, IColorObject>(s.FillColor);
|
||||
d.LineColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.LineColor.GradientStop);
|
||||
d.FillColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.FillColor.GradientStop);
|
||||
return d;
|
||||
}
|
||||
|
||||
public static void CopyPropertyValue(IColorViewModel s, IColorViewModel d, string propertyName = null)
|
||||
{
|
||||
if (propertyName == "LineColor")
|
||||
{
|
||||
CopyPropertyValue(s.LineColor, d.LineColor);
|
||||
d.LineColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.LineColor.GradientStop);
|
||||
}
|
||||
else if (propertyName == "FillColor")
|
||||
{
|
||||
CopyPropertyValue(s.FillColor, d.FillColor);
|
||||
d.FillColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.FillColor.GradientStop);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyPropertyValue((object)s, (object)d, propertyName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
29
AIStudio.Wpf.DiagramDesigner/Helpers/CursorPointManager.cs
Normal file
29
AIStudio.Wpf.DiagramDesigner/Helpers/CursorPointManager.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
/// <summary>
|
||||
/// win8下wpf程序测试成功
|
||||
/// </summary>
|
||||
public class CursorPointManager
|
||||
{
|
||||
#region 得到光标在屏幕上的位置
|
||||
[DllImport("user32")]
|
||||
private static extern bool GetCursorPos(out Point lpPoint);
|
||||
|
||||
/// <summary>
|
||||
/// 获取光标相对于显示器的位置
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Point GetCursorPosition()
|
||||
{
|
||||
Point showPoint = new Point();
|
||||
GetCursorPos(out showPoint);
|
||||
return showPoint;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
45
AIStudio.Wpf.DiagramDesigner/Helpers/DesignerHelper.cs
Normal file
45
AIStudio.Wpf.DiagramDesigner/Helpers/DesignerHelper.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class DesignerHelper
|
||||
{
|
||||
private static bool? _isInDesignMode;
|
||||
|
||||
public static bool IsInDesignMode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_isInDesignMode.HasValue)
|
||||
{
|
||||
_isInDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(FrameworkElement)).Metadata.DefaultValue;
|
||||
}
|
||||
return _isInDesignMode.Value;
|
||||
}
|
||||
}
|
||||
|
||||
#region IsInMainThread
|
||||
|
||||
/// <summary>
|
||||
/// 是否是在主线程中处理
|
||||
/// </summary>
|
||||
public static bool IsInMainThread
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Thread.CurrentThread.IsBackground || Thread.CurrentThread.IsThreadPoolThread) return false;
|
||||
|
||||
if (Thread.CurrentThread.Name == "主线程") return true;
|
||||
|
||||
if (Application.Current == null)
|
||||
return true;
|
||||
|
||||
return Thread.CurrentThread == Application.Current.Dispatcher.Thread;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
94
AIStudio.Wpf.DiagramDesigner/Helpers/DoCommandManager.cs
Normal file
94
AIStudio.Wpf.DiagramDesigner/Helpers/DoCommandManager.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
class DoCommandManager
|
||||
{
|
||||
#region Command定义
|
||||
public class Command
|
||||
{
|
||||
string name;
|
||||
Action action;
|
||||
Action unDoAction;
|
||||
Action clearAction;
|
||||
|
||||
internal Command(string name, Action action, Action unDoAction, Action clearAction)
|
||||
{
|
||||
this.name = name;
|
||||
this.action = action;
|
||||
this.unDoAction = unDoAction;
|
||||
this.clearAction = clearAction;
|
||||
}
|
||||
|
||||
internal void Do() { action(); }
|
||||
internal void UnDo() { unDoAction(); }
|
||||
internal void Clear() { if (clearAction != null) clearAction(); }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return name.ToString();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public Stack<Command> ReDoActionStack { get; private set; }
|
||||
public Stack<Command> UnDoActionStack { get; private set; }
|
||||
|
||||
public int Capacity { get; set; } = 10;
|
||||
|
||||
public DoCommandManager()
|
||||
{
|
||||
ReDoActionStack = new Stack<Command>();
|
||||
UnDoActionStack = new Stack<Command>();
|
||||
}
|
||||
|
||||
public void DoNewCommand(string name, Action action, Action unDoAction, Action clearAction = null, bool doit = true)
|
||||
{
|
||||
if (UnDoActionStack.Count >= Capacity)
|
||||
{
|
||||
//清理
|
||||
var clear = UnDoActionStack.LastOrDefault();
|
||||
clear.Clear();
|
||||
|
||||
UnDoActionStack = new Stack<Command>(UnDoActionStack.Take(Capacity - 1).Reverse());
|
||||
}
|
||||
|
||||
var cmd = new Command(name, action, unDoAction, clearAction);
|
||||
UnDoActionStack.Push(cmd);
|
||||
|
||||
ReDoActionStack.Clear();
|
||||
if (doit)
|
||||
{
|
||||
cmd.Do();
|
||||
}
|
||||
}
|
||||
|
||||
public void UnDo()
|
||||
{
|
||||
if (!CanUnDo)
|
||||
return;
|
||||
|
||||
var cmd = UnDoActionStack.Pop();
|
||||
ReDoActionStack.Push(cmd);
|
||||
cmd.UnDo();
|
||||
}
|
||||
|
||||
public void ReDo()
|
||||
{
|
||||
if (!CanReDo)
|
||||
return;
|
||||
|
||||
var cmd = ReDoActionStack.Pop();
|
||||
UnDoActionStack.Push(cmd);
|
||||
cmd.Do();
|
||||
}
|
||||
|
||||
public bool CanUnDo { get { return UnDoActionStack.Count != 0; } }
|
||||
public bool CanReDo { get { return ReDoActionStack.Count != 0; } }
|
||||
//public IEnumerable<Command> Actions { get { return ReDoActionStack.Reverse().Concat(UnDoActionStack); } }
|
||||
}
|
||||
}
|
||||
18
AIStudio.Wpf.DiagramDesigner/Helpers/DragObject.cs
Normal file
18
AIStudio.Wpf.DiagramDesigner/Helpers/DragObject.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
// Wraps info of the dragged object into a class
|
||||
public class DragObject
|
||||
{
|
||||
public Size? DesiredSize { get; set; }
|
||||
public Type ContentType { get; set; }
|
||||
public string Icon { get; set; }
|
||||
public IColorViewModel ColorViewModel { get; set; }
|
||||
public DesignerItemBase DesignerItem { get; set; }
|
||||
}
|
||||
}
|
||||
18
AIStudio.Wpf.DiagramDesigner/Helpers/EnumExtension.cs
Normal file
18
AIStudio.Wpf.DiagramDesigner/Helpers/EnumExtension.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public static class EnumExtension
|
||||
{
|
||||
public static string GetDescription(this Enum value)
|
||||
{
|
||||
FieldInfo field = value.GetType().GetField(value.ToString());
|
||||
DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
|
||||
|
||||
return attribute == null ? value.ToString() : attribute.Description;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
25
AIStudio.Wpf.DiagramDesigner/Helpers/EventToCommandArgs.cs
Normal file
25
AIStudio.Wpf.DiagramDesigner/Helpers/EventToCommandArgs.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class EventToCommandArgs
|
||||
{
|
||||
public Object Sender { get; private set; }
|
||||
public ICommand CommandRan { get; private set; }
|
||||
public Object CommandParameter { get; private set; }
|
||||
public EventArgs EventArgs { get; private set; }
|
||||
|
||||
public EventToCommandArgs(Object sender, ICommand commandRan, Object commandParameter, EventArgs eventArgs)
|
||||
{
|
||||
this.Sender = sender;
|
||||
this.CommandRan = commandRan;
|
||||
this.CommandParameter = commandParameter;
|
||||
this.EventArgs = eventArgs;
|
||||
}
|
||||
}
|
||||
}
|
||||
264
AIStudio.Wpf.DiagramDesigner/Helpers/Extention.Object.cs
Normal file
264
AIStudio.Wpf.DiagramDesigner/Helpers/Extention.Object.cs
Normal file
@@ -0,0 +1,264 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public static partial class Extention
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
static Extention()
|
||||
{
|
||||
JsonSerializerSettings setting = new JsonSerializerSettings();
|
||||
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
|
||||
{
|
||||
//日期类型默认格式化处理
|
||||
setting.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
|
||||
setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||
setting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
return setting;
|
||||
});
|
||||
}
|
||||
|
||||
private static BindingFlags _bindingFlags { get; }
|
||||
= BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static;
|
||||
|
||||
/// <summary>
|
||||
/// 将一个object对象序列化,返回一个byte[]
|
||||
/// </summary>
|
||||
/// <param name="obj">能序列化的对象</param>
|
||||
/// <returns></returns>
|
||||
public static byte[] ToBytes(this object obj)
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
IFormatter formatter = new BinaryFormatter();
|
||||
formatter.Serialize(ms, obj);
|
||||
return ms.GetBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断是否为Null或者空
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <returns></returns>
|
||||
public static bool IsNullOrEmpty(this object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
string objStr = obj.ToString();
|
||||
return string.IsNullOrEmpty(objStr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象序列化成Json字符串
|
||||
/// </summary>
|
||||
/// <param name="obj">需要序列化的对象</param>
|
||||
/// <returns></returns>
|
||||
public static string ToJson(this object obj)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj);
|
||||
}
|
||||
|
||||
public static JsonSerializerSettings Settings { get; set; } = new JsonSerializerSettings
|
||||
{
|
||||
DateFormatString = "yyyy-MM-dd HH:mm:ss.fff",
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
};
|
||||
|
||||
public static string ToStandardTimeFormatJson(this object obj)
|
||||
{
|
||||
return JsonConvert.SerializeObject(obj, Settings);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 实体类转json数据,速度快
|
||||
/// </summary>
|
||||
/// <param name="t">实体类</param>
|
||||
/// <returns></returns>
|
||||
public static string EntityToJson(this object t)
|
||||
{
|
||||
if (t == null)
|
||||
return null;
|
||||
string jsonStr = "";
|
||||
jsonStr += "{";
|
||||
PropertyInfo[] infos = t.GetType().GetProperties();
|
||||
for (int i = 0; i < infos.Length; i++)
|
||||
{
|
||||
jsonStr = jsonStr + "\"" + infos[i].Name + "\":\"" + infos[i].GetValue(t).ToString() + "\"";
|
||||
if (i != infos.Length - 1)
|
||||
jsonStr += ",";
|
||||
}
|
||||
jsonStr += "}";
|
||||
return jsonStr;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 深复制
|
||||
///// </summary>
|
||||
///// <typeparam name="T">类型</typeparam>
|
||||
///// <param name="obj">对象</param>
|
||||
///// <returns></returns>
|
||||
//public static T DeepClone<T>(this T obj) where T : class
|
||||
//{
|
||||
// if (obj == null)
|
||||
// return null;
|
||||
|
||||
// return obj.ToJson().ToObject<T>();
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象序列化为XML字符串
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型</typeparam>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <returns></returns>
|
||||
public static string ToXmlStr<T>(this T obj)
|
||||
{
|
||||
var jsonStr = obj.ToJson();
|
||||
var xmlDoc = JsonConvert.DeserializeXmlNode(jsonStr);
|
||||
string xmlDocStr = xmlDoc.InnerXml;
|
||||
|
||||
return xmlDocStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将对象序列化为XML字符串
|
||||
/// </summary>
|
||||
/// <typeparam name="T">对象类型</typeparam>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <param name="rootNodeName">根节点名(建议设为xml)</param>
|
||||
/// <returns></returns>
|
||||
public static string ToXmlStr<T>(this T obj, string rootNodeName)
|
||||
{
|
||||
var jsonStr = obj.ToJson();
|
||||
var xmlDoc = JsonConvert.DeserializeXmlNode(jsonStr, rootNodeName);
|
||||
string xmlDocStr = xmlDoc.InnerXml;
|
||||
|
||||
return xmlDocStr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否拥有某属性
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <param name="propertyName">属性名</param>
|
||||
/// <returns></returns>
|
||||
public static bool ContainsProperty(this object obj, string propertyName)
|
||||
{
|
||||
return obj.GetType().GetProperty(propertyName, _bindingFlags) != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取某属性值
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <param name="propertyName">属性名</param>
|
||||
/// <returns></returns>
|
||||
public static object GetPropertyValue(this object obj, string propertyName)
|
||||
{
|
||||
return obj.GetType().GetProperty(propertyName, _bindingFlags).GetValue(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置某属性值
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <param name="propertyName">属性名</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <returns></returns>
|
||||
public static void SetPropertyValue(this object obj, string propertyName, object value)
|
||||
{
|
||||
obj.GetType().GetProperty(propertyName, _bindingFlags).SetValue(obj, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否拥有某字段
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <param name="fieldName">字段名</param>
|
||||
/// <returns></returns>
|
||||
public static bool ContainsField(this object obj, string fieldName)
|
||||
{
|
||||
return obj.GetType().GetField(fieldName, _bindingFlags) != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取某字段值
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <param name="fieldName">字段名</param>
|
||||
/// <returns></returns>
|
||||
public static object GetGetFieldValue(this object obj, string fieldName)
|
||||
{
|
||||
return obj.GetType().GetField(fieldName, _bindingFlags).GetValue(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置某字段值
|
||||
/// </summary>
|
||||
/// <param name="obj">对象</param>
|
||||
/// <param name="fieldName">字段名</param>
|
||||
/// <param name="value">值</param>
|
||||
/// <returns></returns>
|
||||
public static void SetFieldValue(this object obj, string fieldName, object value)
|
||||
{
|
||||
obj.GetType().GetField(fieldName, _bindingFlags).SetValue(obj, value);
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 改变实体类型
|
||||
///// </summary>
|
||||
///// <param name="obj">对象</param>
|
||||
///// <param name="targetType">目标类型</param>
|
||||
///// <returns></returns>
|
||||
//public static object ChangeType(this object obj, Type targetType)
|
||||
//{
|
||||
// return obj.ToJson().ToObject(targetType);
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 改变实体类型
|
||||
///// </summary>
|
||||
///// <typeparam name="T">目标泛型</typeparam>
|
||||
///// <param name="obj">对象</param>
|
||||
///// <returns></returns>
|
||||
//public static T ChangeType<T>(this object obj)
|
||||
//{
|
||||
// return obj.ToJson().ToObject<T>();
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 改变类型
|
||||
/// </summary>
|
||||
/// <param name="obj">原对象</param>
|
||||
/// <param name="targetType">目标类型</param>
|
||||
/// <returns></returns>
|
||||
public static object ChangeType_ByConvert(this object obj, Type targetType)
|
||||
{
|
||||
object resObj;
|
||||
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
|
||||
{
|
||||
NullableConverter newNullableConverter = new NullableConverter(targetType);
|
||||
resObj = newNullableConverter.ConvertFrom(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
resObj = Convert.ChangeType(obj, targetType);
|
||||
}
|
||||
|
||||
return resObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
AIStudio.Wpf.DiagramDesigner/Helpers/IPathFinder.cs
Normal file
14
AIStudio.Wpf.DiagramDesigner/Helpers/IPathFinder.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public interface IPathFinder
|
||||
{
|
||||
List<Point> GetConnectionLine(ConnectorInfo source, ConnectorInfo sink, bool showLastLine, bool sourceInnerPoint = false);
|
||||
List<Point> GetConnectionLine(ConnectorInfo source, Point sinkPoint, ConnectorOrientation preferredOrientation, bool showLastLine, bool isInnerPoint = false);
|
||||
}
|
||||
}
|
||||
697
AIStudio.Wpf.DiagramDesigner/Helpers/OrthogonalPathFinder.cs
Normal file
697
AIStudio.Wpf.DiagramDesigner/Helpers/OrthogonalPathFinder.cs
Normal file
@@ -0,0 +1,697 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
// Note: I couldn't find a useful open source library that does
|
||||
// orthogonal routing so started to write something on my own.
|
||||
// Categorize this as a quick and dirty short term solution.
|
||||
// I will keep on searching.
|
||||
|
||||
// Helper class to provide an orthogonal connection path
|
||||
public class OrthogonalPathFinder : IPathFinder
|
||||
{
|
||||
private const int const_margin = 20;
|
||||
|
||||
public List<Point> GetConnectionLine(ConnectorInfo source, ConnectorInfo sink, bool showLastLine, bool sourceInnerPoint = false)
|
||||
{
|
||||
List<Point> linePoints = new List<Point>();
|
||||
int margin1 = sourceInnerPoint ? 0 : const_margin;
|
||||
int margin2 = const_margin;
|
||||
|
||||
Rect rectSource = GetRectWithMargin(source, margin1);
|
||||
Rect rectSink = GetRectWithMargin(sink, margin2);
|
||||
|
||||
Point startPoint = GetOffsetPoint(source, rectSource, sourceInnerPoint);
|
||||
Point endPoint = GetOffsetPoint(sink, rectSink);
|
||||
|
||||
linePoints.Add(startPoint);
|
||||
Point currentPoint = startPoint;
|
||||
|
||||
if (!rectSink.Contains(currentPoint) && !rectSource.Contains(endPoint))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
#region source node
|
||||
|
||||
if (IsPointVisible(currentPoint, endPoint, new Rect[] { rectSource, rectSink }))
|
||||
{
|
||||
linePoints.Add(endPoint);
|
||||
currentPoint = endPoint;
|
||||
break;
|
||||
}
|
||||
|
||||
Point neighbour = GetNearestVisibleNeighborSink(currentPoint, endPoint, sink, rectSource, rectSink);
|
||||
if (!double.IsNaN(neighbour.X))
|
||||
{
|
||||
linePoints.Add(neighbour);
|
||||
linePoints.Add(endPoint);
|
||||
currentPoint = endPoint;
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentPoint == startPoint)
|
||||
{
|
||||
bool flag;
|
||||
Point n = GetNearestNeighborSource(source, endPoint, rectSource, rectSink, out flag, sourceInnerPoint);
|
||||
if (linePoints.Contains(n))
|
||||
{
|
||||
break;
|
||||
}
|
||||
linePoints.Add(n);
|
||||
currentPoint = n;
|
||||
|
||||
if (!IsRectVisible(currentPoint, rectSink, new Rect[] { rectSource }))
|
||||
{
|
||||
Point n1, n2;
|
||||
GetOppositeCorners(source.Orientation, rectSource, out n1, out n2, sourceInnerPoint);
|
||||
if (flag)
|
||||
{
|
||||
linePoints.Add(n1);
|
||||
currentPoint = n1;
|
||||
}
|
||||
else
|
||||
{
|
||||
linePoints.Add(n2);
|
||||
currentPoint = n2;
|
||||
}
|
||||
if (!IsRectVisible(currentPoint, rectSink, new Rect[] { rectSource }))
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
linePoints.Add(n2);
|
||||
currentPoint = n2;
|
||||
}
|
||||
else
|
||||
{
|
||||
linePoints.Add(n1);
|
||||
currentPoint = n1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region sink node
|
||||
|
||||
else // from here on we jump to the sink node
|
||||
{
|
||||
Point n1, n2; // neighbour corner
|
||||
Point s1, s2; // opposite corner
|
||||
GetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);
|
||||
GetOppositeCorners(sink.Orientation, rectSink, out n1, out n2);
|
||||
|
||||
bool n1Visible = IsPointVisible(currentPoint, n1, new Rect[] { rectSource, rectSink });
|
||||
bool n2Visible = IsPointVisible(currentPoint, n2, new Rect[] { rectSource, rectSink });
|
||||
|
||||
if (n1Visible && n2Visible)
|
||||
{
|
||||
if (rectSource.Contains(n1))
|
||||
{
|
||||
linePoints.Add(n2);
|
||||
if (rectSource.Contains(s2))
|
||||
{
|
||||
linePoints.Add(n1);
|
||||
linePoints.Add(s1);
|
||||
}
|
||||
else
|
||||
linePoints.Add(s2);
|
||||
|
||||
linePoints.Add(endPoint);
|
||||
currentPoint = endPoint;
|
||||
break;
|
||||
}
|
||||
|
||||
if (rectSource.Contains(n2))
|
||||
{
|
||||
linePoints.Add(n1);
|
||||
if (rectSource.Contains(s1))
|
||||
{
|
||||
linePoints.Add(n2);
|
||||
linePoints.Add(s2);
|
||||
}
|
||||
else
|
||||
linePoints.Add(s1);
|
||||
|
||||
linePoints.Add(endPoint);
|
||||
currentPoint = endPoint;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
|
||||
{
|
||||
linePoints.Add(n1);
|
||||
if (rectSource.Contains(s1))
|
||||
{
|
||||
linePoints.Add(n2);
|
||||
linePoints.Add(s2);
|
||||
}
|
||||
else
|
||||
linePoints.Add(s1);
|
||||
linePoints.Add(endPoint);
|
||||
currentPoint = endPoint;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
linePoints.Add(n2);
|
||||
if (rectSource.Contains(s2))
|
||||
{
|
||||
linePoints.Add(n1);
|
||||
linePoints.Add(s1);
|
||||
}
|
||||
else
|
||||
linePoints.Add(s2);
|
||||
linePoints.Add(endPoint);
|
||||
currentPoint = endPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (n1Visible)
|
||||
{
|
||||
linePoints.Add(n1);
|
||||
if (rectSource.Contains(s1))
|
||||
{
|
||||
linePoints.Add(n2);
|
||||
linePoints.Add(s2);
|
||||
}
|
||||
else
|
||||
linePoints.Add(s1);
|
||||
linePoints.Add(endPoint);
|
||||
currentPoint = endPoint;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
linePoints.Add(n2);
|
||||
if (rectSource.Contains(s2))
|
||||
{
|
||||
linePoints.Add(n1);
|
||||
linePoints.Add(s1);
|
||||
}
|
||||
else
|
||||
linePoints.Add(s2);
|
||||
linePoints.Add(endPoint);
|
||||
currentPoint = endPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
linePoints.Add(endPoint);
|
||||
}
|
||||
|
||||
linePoints = OptimizeLinePoints(linePoints, new Rect[] { rectSource, rectSink }, source.Orientation, sink.Orientation);
|
||||
|
||||
CheckPathEnd(source, sink, showLastLine, linePoints, sourceInnerPoint);
|
||||
|
||||
return linePoints;
|
||||
}
|
||||
|
||||
public List<Point> GetConnectionLine(ConnectorInfo source, Point sinkPoint, ConnectorOrientation preferredOrientation, bool showLastLine, bool isInnerPoint = false)
|
||||
{
|
||||
List<Point> linePoints = new List<Point>();
|
||||
int margin = isInnerPoint ? 0 : const_margin;
|
||||
|
||||
Rect rectSource = GetRectWithMargin(source, margin);
|
||||
Point startPoint = GetOffsetPoint(source, rectSource, isInnerPoint);
|
||||
Point endPoint = sinkPoint;
|
||||
|
||||
linePoints.Add(startPoint);
|
||||
Point currentPoint = startPoint;
|
||||
|
||||
if (!rectSource.Contains(endPoint))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (IsPointVisible(currentPoint, endPoint, new Rect[] { rectSource }))
|
||||
{
|
||||
linePoints.Add(endPoint);
|
||||
break;
|
||||
}
|
||||
|
||||
bool sideFlag;
|
||||
Point n = GetNearestNeighborSource(source, endPoint, rectSource, out sideFlag, isInnerPoint);
|
||||
linePoints.Add(n);
|
||||
currentPoint = n;
|
||||
|
||||
if (IsPointVisible(currentPoint, endPoint, new Rect[] { rectSource }))
|
||||
{
|
||||
linePoints.Add(endPoint);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Point n1, n2;
|
||||
GetOppositeCorners(source.Orientation, rectSource, out n1, out n2, isInnerPoint);
|
||||
if (sideFlag)
|
||||
linePoints.Add(n1);
|
||||
else
|
||||
linePoints.Add(n2);
|
||||
|
||||
linePoints.Add(endPoint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
linePoints.Add(endPoint);
|
||||
}
|
||||
|
||||
if (preferredOrientation != ConnectorOrientation.None)
|
||||
linePoints = OptimizeLinePoints(linePoints, new Rect[] { rectSource }, source.Orientation, preferredOrientation);
|
||||
else
|
||||
linePoints = OptimizeLinePoints(linePoints, new Rect[] { rectSource }, source.Orientation, GetOpositeOrientation(source.Orientation));
|
||||
|
||||
if (!showLastLine)
|
||||
{
|
||||
linePoints.Insert(0, source.Position);
|
||||
}
|
||||
|
||||
return linePoints;
|
||||
}
|
||||
|
||||
private static List<Point> OptimizeLinePoints(List<Point> linePoints, Rect[] rectangles, ConnectorOrientation sourceOrientation, ConnectorOrientation sinkOrientation)
|
||||
{
|
||||
List<Point> points = new List<Point>();
|
||||
int cut = 0;
|
||||
|
||||
for (int i = 0; i < linePoints.Count; i++)
|
||||
{
|
||||
if (i >= cut)
|
||||
{
|
||||
for (int k = linePoints.Count - 1; k > i; k--)
|
||||
{
|
||||
if (IsPointVisible(linePoints[i], linePoints[k], rectangles))
|
||||
{
|
||||
cut = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
points.Add(linePoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#region Line
|
||||
for (int j = 0; j < points.Count - 1; j++)
|
||||
{
|
||||
if (points[j].X != points[j + 1].X && points[j].Y != points[j + 1].Y)
|
||||
{
|
||||
ConnectorOrientation orientationFrom;
|
||||
ConnectorOrientation orientationTo;
|
||||
|
||||
// orientation from point
|
||||
if (j == 0)
|
||||
orientationFrom = sourceOrientation;
|
||||
else
|
||||
orientationFrom = GetOrientation(points[j], points[j - 1]);
|
||||
|
||||
// orientation to pint
|
||||
if (j == points.Count - 2)
|
||||
orientationTo = sinkOrientation;
|
||||
else
|
||||
orientationTo = GetOrientation(points[j + 1], points[j + 2]);
|
||||
|
||||
|
||||
if ((orientationFrom == ConnectorOrientation.Left || orientationFrom == ConnectorOrientation.Right) &&
|
||||
(orientationTo == ConnectorOrientation.Left || orientationTo == ConnectorOrientation.Right))
|
||||
{
|
||||
double centerX = Math.Min(points[j].X, points[j + 1].X) + Math.Abs(points[j].X - points[j + 1].X) / 2;
|
||||
points.Insert(j + 1, new Point(centerX, points[j].Y));
|
||||
points.Insert(j + 2, new Point(centerX, points[j + 2].Y));
|
||||
if (points.Count - 1 > j + 3)
|
||||
points.RemoveAt(j + 3);
|
||||
return points;
|
||||
}
|
||||
|
||||
if ((orientationFrom == ConnectorOrientation.Top || orientationFrom == ConnectorOrientation.Bottom) &&
|
||||
(orientationTo == ConnectorOrientation.Top || orientationTo == ConnectorOrientation.Bottom))
|
||||
{
|
||||
double centerY = Math.Min(points[j].Y, points[j + 1].Y) + Math.Abs(points[j].Y - points[j + 1].Y) / 2;
|
||||
points.Insert(j + 1, new Point(points[j].X, centerY));
|
||||
points.Insert(j + 2, new Point(points[j + 2].X, centerY));
|
||||
if (points.Count - 1 > j + 3)
|
||||
points.RemoveAt(j + 3);
|
||||
return points;
|
||||
}
|
||||
|
||||
if ((orientationFrom == ConnectorOrientation.Left || orientationFrom == ConnectorOrientation.Right) &&
|
||||
(orientationTo == ConnectorOrientation.Top || orientationTo == ConnectorOrientation.Bottom))
|
||||
{
|
||||
points.Insert(j + 1, new Point(points[j + 1].X, points[j].Y));
|
||||
return points;
|
||||
}
|
||||
|
||||
if ((orientationFrom == ConnectorOrientation.Top || orientationFrom == ConnectorOrientation.Bottom) &&
|
||||
(orientationTo == ConnectorOrientation.Left || orientationTo == ConnectorOrientation.Right))
|
||||
{
|
||||
points.Insert(j + 1, new Point(points[j].X, points[j + 1].Y));
|
||||
return points;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private static ConnectorOrientation GetOrientation(Point p1, Point p2)
|
||||
{
|
||||
if (p1.X == p2.X)
|
||||
{
|
||||
if (p1.Y >= p2.Y)
|
||||
return ConnectorOrientation.Bottom;
|
||||
else
|
||||
return ConnectorOrientation.Top;
|
||||
}
|
||||
else if (p1.Y == p2.Y)
|
||||
{
|
||||
if (p1.X >= p2.X)
|
||||
return ConnectorOrientation.Right;
|
||||
else
|
||||
return ConnectorOrientation.Left;
|
||||
}
|
||||
throw new Exception("Failed to retrieve orientation");
|
||||
}
|
||||
|
||||
private static Orientation GetOrientation(ConnectorOrientation sourceOrientation, bool isInnerPoint)
|
||||
{
|
||||
if (isInnerPoint)
|
||||
{
|
||||
return Orientation.Vertical;
|
||||
}
|
||||
switch (sourceOrientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
return Orientation.Horizontal;
|
||||
case ConnectorOrientation.Top:
|
||||
return Orientation.Vertical;
|
||||
case ConnectorOrientation.Right:
|
||||
return Orientation.Horizontal;
|
||||
case ConnectorOrientation.Bottom:
|
||||
return Orientation.Vertical;
|
||||
default:
|
||||
throw new Exception("Unknown ConnectorOrientation");
|
||||
}
|
||||
}
|
||||
|
||||
private static Point GetNearestNeighborSource(ConnectorInfo source, Point endPoint, Rect rectSource, Rect rectSink, out bool flag, bool isInnerPoint)
|
||||
{
|
||||
Point n1, n2; // neighbors
|
||||
GetNeighborCorners(source.Orientation, rectSource, out n1, out n2, isInnerPoint);
|
||||
|
||||
if (rectSink.Contains(n1))
|
||||
{
|
||||
flag = false;
|
||||
return n2;
|
||||
}
|
||||
|
||||
if (rectSink.Contains(n2))
|
||||
{
|
||||
flag = true;
|
||||
return n1;
|
||||
}
|
||||
|
||||
if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
|
||||
{
|
||||
flag = true;
|
||||
return n1;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = false;
|
||||
return n2;
|
||||
}
|
||||
}
|
||||
|
||||
private static Point GetNearestNeighborSource(ConnectorInfo source, Point endPoint, Rect rectSource, out bool flag, bool isInnerPoint)
|
||||
{
|
||||
Point n1, n2; // neighbors
|
||||
GetNeighborCorners(source.Orientation, rectSource, out n1, out n2, isInnerPoint);
|
||||
|
||||
if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
|
||||
{
|
||||
flag = true;
|
||||
return n1;
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = false;
|
||||
return n2;
|
||||
}
|
||||
}
|
||||
|
||||
private static Point GetNearestVisibleNeighborSink(Point currentPoint, Point endPoint, ConnectorInfo sink, Rect rectSource, Rect rectSink)
|
||||
{
|
||||
Point s1, s2; // neighbors on sink side
|
||||
GetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);
|
||||
|
||||
bool flag1 = IsPointVisible(currentPoint, s1, new Rect[] { rectSource, rectSink });
|
||||
bool flag2 = IsPointVisible(currentPoint, s2, new Rect[] { rectSource, rectSink });
|
||||
|
||||
if (flag1) // s1 visible
|
||||
{
|
||||
if (flag2) // s1 and s2 visible
|
||||
{
|
||||
if (rectSink.Contains(s1))
|
||||
return s2;
|
||||
|
||||
if (rectSink.Contains(s2))
|
||||
return s1;
|
||||
|
||||
if ((Distance(s1, endPoint) <= Distance(s2, endPoint)))
|
||||
return s1;
|
||||
else
|
||||
return s2;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return s1;
|
||||
}
|
||||
}
|
||||
else // s1 not visible
|
||||
{
|
||||
if (flag2) // only s2 visible
|
||||
{
|
||||
return s2;
|
||||
}
|
||||
else // s1 and s2 not visible
|
||||
{
|
||||
return new Point(double.NaN, double.NaN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsPointVisible(Point fromPoint, Point targetPoint, Rect[] rectangles)
|
||||
{
|
||||
foreach (Rect rect in rectangles)
|
||||
{
|
||||
if (RectangleIntersectsLine(rect, fromPoint, targetPoint))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool IsRectVisible(Point fromPoint, Rect targetRect, Rect[] rectangles)
|
||||
{
|
||||
if (IsPointVisible(fromPoint, targetRect.TopLeft, rectangles))
|
||||
return true;
|
||||
|
||||
if (IsPointVisible(fromPoint, targetRect.TopRight, rectangles))
|
||||
return true;
|
||||
|
||||
if (IsPointVisible(fromPoint, targetRect.BottomLeft, rectangles))
|
||||
return true;
|
||||
|
||||
if (IsPointVisible(fromPoint, targetRect.BottomRight, rectangles))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool RectangleIntersectsLine(Rect rect, Point startPoint, Point endPoint)
|
||||
{
|
||||
rect.Inflate(-1, -1);
|
||||
return rect.IntersectsWith(new Rect(startPoint, endPoint));
|
||||
}
|
||||
|
||||
private static void GetOppositeCorners(ConnectorOrientation orientation, Rect rect, out Point n1, out Point n2, bool isInnerPoint = false)
|
||||
{
|
||||
if (isInnerPoint)
|
||||
{
|
||||
n1 = rect.Location; n2 = rect.Location;
|
||||
return;
|
||||
}
|
||||
switch (orientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
n1 = rect.TopRight; n2 = rect.BottomRight;
|
||||
break;
|
||||
case ConnectorOrientation.Top:
|
||||
n1 = rect.BottomLeft; n2 = rect.BottomRight;
|
||||
break;
|
||||
case ConnectorOrientation.Right:
|
||||
n1 = rect.TopLeft; n2 = rect.BottomLeft;
|
||||
break;
|
||||
case ConnectorOrientation.Bottom:
|
||||
n1 = rect.TopLeft; n2 = rect.TopRight;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("No opposite corners found!");
|
||||
}
|
||||
}
|
||||
|
||||
private static void GetNeighborCorners(ConnectorOrientation orientation, Rect rect, out Point n1, out Point n2, bool isInnerPoint = false)
|
||||
{
|
||||
if (isInnerPoint)
|
||||
{
|
||||
n1 = rect.Location; n2 = rect.Location;
|
||||
return;
|
||||
}
|
||||
switch (orientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
n1 = rect.TopLeft; n2 = rect.BottomLeft;
|
||||
break;
|
||||
case ConnectorOrientation.Top:
|
||||
n1 = rect.TopLeft; n2 = rect.TopRight;
|
||||
break;
|
||||
case ConnectorOrientation.Right:
|
||||
n1 = rect.TopRight; n2 = rect.BottomRight;
|
||||
break;
|
||||
case ConnectorOrientation.Bottom:
|
||||
n1 = rect.BottomLeft; n2 = rect.BottomRight;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("No neighour corners found!");
|
||||
}
|
||||
}
|
||||
|
||||
private static double Distance(Point p1, Point p2)
|
||||
{
|
||||
return Point.Subtract(p1, p2).Length;
|
||||
}
|
||||
|
||||
private static Rect GetRectWithMargin(ConnectorInfo connectorThumb, double margin)
|
||||
{
|
||||
Rect rect = new Rect(connectorThumb.DesignerItemLeft,
|
||||
connectorThumb.DesignerItemTop,
|
||||
0,
|
||||
0);
|
||||
|
||||
rect.Inflate(margin, margin);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
private static Point GetOffsetPoint(ConnectorInfo connector, Rect rect, bool isInnerPoint = false)
|
||||
{
|
||||
Point offsetPoint = new Point();
|
||||
if (isInnerPoint)
|
||||
{
|
||||
offsetPoint = new Point(connector.Position.X, connector.Position.Y);
|
||||
return offsetPoint;
|
||||
}
|
||||
|
||||
switch (connector.Orientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
offsetPoint = new Point(rect.Left, connector.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Top:
|
||||
offsetPoint = new Point(connector.Position.X, rect.Top);
|
||||
break;
|
||||
case ConnectorOrientation.Right:
|
||||
offsetPoint = new Point(rect.Right, connector.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Bottom:
|
||||
offsetPoint = new Point(connector.Position.X, rect.Bottom);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return offsetPoint;
|
||||
}
|
||||
|
||||
private static void CheckPathEnd(ConnectorInfo source, ConnectorInfo sink, bool showLastLine, List<Point> linePoints, bool sourceInnerPoint)
|
||||
{
|
||||
if (showLastLine)
|
||||
{
|
||||
Point startPoint = new Point(0, 0);
|
||||
Point endPoint = new Point(0, 0);
|
||||
double marginPath = 15;
|
||||
switch (source.Orientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
startPoint = new Point(source.Position.X - marginPath, source.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Top:
|
||||
startPoint = new Point(source.Position.X, source.Position.Y - marginPath);
|
||||
break;
|
||||
case ConnectorOrientation.Right:
|
||||
startPoint = new Point(source.Position.X + marginPath, source.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Bottom:
|
||||
startPoint = new Point(source.Position.X, source.Position.Y + marginPath);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (sourceInnerPoint)
|
||||
{
|
||||
startPoint = new Point(source.Position.X, source.Position.Y);
|
||||
}
|
||||
|
||||
switch (sink.Orientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
endPoint = new Point(sink.Position.X - marginPath, sink.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Top:
|
||||
endPoint = new Point(sink.Position.X, sink.Position.Y - marginPath);
|
||||
break;
|
||||
case ConnectorOrientation.Right:
|
||||
endPoint = new Point(sink.Position.X + marginPath, sink.Position.Y);
|
||||
break;
|
||||
case ConnectorOrientation.Bottom:
|
||||
endPoint = new Point(sink.Position.X, sink.Position.Y + marginPath);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
linePoints.Insert(0, startPoint);
|
||||
linePoints.Add(endPoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
linePoints.Insert(0, source.Position);
|
||||
linePoints.Add(sink.Position);
|
||||
}
|
||||
}
|
||||
|
||||
private static ConnectorOrientation GetOpositeOrientation(ConnectorOrientation connectorOrientation)
|
||||
{
|
||||
switch (connectorOrientation)
|
||||
{
|
||||
case ConnectorOrientation.Left:
|
||||
return ConnectorOrientation.Right;
|
||||
case ConnectorOrientation.Top:
|
||||
return ConnectorOrientation.Bottom;
|
||||
case ConnectorOrientation.Right:
|
||||
return ConnectorOrientation.Left;
|
||||
case ConnectorOrientation.Bottom:
|
||||
return ConnectorOrientation.Top;
|
||||
default:
|
||||
return ConnectorOrientation.Top;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
AIStudio.Wpf.DiagramDesigner/Helpers/PointHelper.cs
Normal file
47
AIStudio.Wpf.DiagramDesigner/Helpers/PointHelper.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class PointHelper
|
||||
{
|
||||
public static Point GetPointForConnector(FullyCreatedConnectorInfo connector)
|
||||
{
|
||||
Point point = new Point();
|
||||
if (connector.IsInnerPoint)
|
||||
{
|
||||
point = new Point(connector.DataItem.Left + connector.DataItem.ItemWidth * connector.XRatio,
|
||||
connector.DataItem.Top + connector.DataItem.ItemHeight * connector.YRatio);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
switch (connector.Orientation)
|
||||
{
|
||||
case ConnectorOrientation.Top:
|
||||
point = new Point(connector.DataItem.Left + (connector.DataItem.ItemWidth / 2), connector.DataItem.Top);
|
||||
break;
|
||||
case ConnectorOrientation.Bottom:
|
||||
point = new Point(connector.DataItem.Left + (connector.DataItem.ItemWidth / 2), (connector.DataItem.Top + connector.DataItem.ItemHeight));
|
||||
break;
|
||||
case ConnectorOrientation.Right:
|
||||
point = new Point(connector.DataItem.Left + connector.DataItem.ItemWidth, connector.DataItem.Top + (connector.DataItem.ItemHeight / 2));
|
||||
break;
|
||||
case ConnectorOrientation.Left:
|
||||
point = new Point(connector.DataItem.Left, connector.DataItem.Top + (connector.DataItem.ItemHeight / 2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
85
AIStudio.Wpf.DiagramDesigner/Helpers/SegmentHelper.cs
Normal file
85
AIStudio.Wpf.DiagramDesigner/Helpers/SegmentHelper.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class SegmentHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获得贝塞尔曲线
|
||||
/// </summary>
|
||||
/// <param name="currentPt">当前点</param>
|
||||
/// <param name="lastPt">上一个点</param>
|
||||
/// <param name="nextPt1">下一个点1</param>
|
||||
/// <param name="nextPt2">下一个点2</param>
|
||||
/// <returns></returns>
|
||||
public static BezierSegment GetBezierSegment(Point currentPt, Point lastPt, Point nextPt1, Point nextPt2)
|
||||
{
|
||||
//计算中点
|
||||
var lastC = GetCenterPoint(lastPt, currentPt);
|
||||
var nextC1 = GetCenterPoint(currentPt, nextPt1); //贝塞尔控制点
|
||||
var nextC2 = GetCenterPoint(nextPt1, nextPt2);
|
||||
|
||||
//计算相邻中点连线跟目的点的垂足
|
||||
//效果并不算太好,因为可能点在两个线上或者线的延长线上,计算会有误差
|
||||
//所以就直接使用中点平移方法。
|
||||
//var C1 = GetFootPoint(lastC, nextC1, currentPt);
|
||||
//var C2 = GetFootPoint(nextC1, nextC2, nextPt1);
|
||||
|
||||
|
||||
//计算“相邻中点”的中点
|
||||
var c1 = GetCenterPoint(lastC, nextC1);
|
||||
var c2 = GetCenterPoint(nextC1, nextC2);
|
||||
|
||||
|
||||
//计算【"中点"的中点】需要的点位移
|
||||
var controlPtOffset1 = currentPt - c1;
|
||||
var controlPtOffset2 = nextPt1 - c2;
|
||||
|
||||
//移动控制点
|
||||
var controlPt1 = nextC1 + controlPtOffset1;
|
||||
var controlPt2 = nextC1 + controlPtOffset2;
|
||||
|
||||
//如果觉得曲线幅度太大,可以将控制点向当前点靠近一定的系数。
|
||||
controlPt1 = controlPt1 + 0 * (currentPt - controlPt1);
|
||||
controlPt2 = controlPt2 + 0 * (nextPt1 - controlPt2);
|
||||
|
||||
var bzs = new BezierSegment(controlPt1, controlPt2, nextPt1, true);
|
||||
return bzs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 过c点做A和B连线的垂足
|
||||
/// </summary>
|
||||
/// <param name="aPoint"></param>
|
||||
/// <param name="bPoint"></param>
|
||||
/// <param name="cPoint"></param>
|
||||
/// <returns></returns>
|
||||
private static Point GetFootPoint(Point aPoint, Point bPoint, Point cPoint)
|
||||
{
|
||||
//设三点坐标是A,B,C,AB构成直线,C是线外的点
|
||||
//三点对边距离是a,b,c,垂足为D,
|
||||
//根据距离推导公式得:AD距离是(b平方-a平方+c平方)/2c
|
||||
//本人数学不好,可能没考虑点c在线ab上的情况
|
||||
var offsetADist = (Math.Pow(cPoint.X - aPoint.X, 2) + Math.Pow(cPoint.Y - aPoint.Y, 2) - Math.Pow(bPoint.X - cPoint.X, 2) - Math.Pow(bPoint.Y - cPoint.Y, 2) + Math.Pow(aPoint.X - bPoint.X, 2) + Math.Pow(aPoint.Y - bPoint.Y, 2)) / (2 * GetDistance(aPoint, bPoint));
|
||||
|
||||
var v = bPoint - aPoint;
|
||||
var distab = GetDistance(aPoint, bPoint);
|
||||
var offsetVector = v * offsetADist / distab;
|
||||
return aPoint + offsetVector;
|
||||
}
|
||||
|
||||
private static Point GetCenterPoint(Point pt1, Point pt2)
|
||||
{
|
||||
return new Point((pt1.X + pt2.X) / 2, (pt1.Y + pt2.Y) / 2);
|
||||
}
|
||||
|
||||
private static double GetDistance(Point pt1, Point pt2)
|
||||
{
|
||||
return Math.Sqrt(Math.Pow(pt1.X - pt2.X, 2) + Math.Pow(pt1.Y - pt2.Y, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
29
AIStudio.Wpf.DiagramDesigner/Helpers/ToolBoxData.cs
Normal file
29
AIStudio.Wpf.DiagramDesigner/Helpers/ToolBoxData.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Helpers
|
||||
{
|
||||
public class ToolBoxData
|
||||
{
|
||||
public string Text { get; protected set; }
|
||||
public string Icon { get; protected set; }
|
||||
public Type Type { get; protected set; }
|
||||
public IColorViewModel ColorViewModel { get; set; }
|
||||
public double Width { get; set; }
|
||||
public double Height { get; set; }
|
||||
|
||||
public object Addition { get; set; }
|
||||
|
||||
public ToolBoxData(string text, string icon, Type type, double width, double height)
|
||||
{
|
||||
this.Text = text;
|
||||
this.Icon = icon;
|
||||
this.Type = type;
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
this.ColorViewModel = new ColorViewModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
37
AIStudio.Wpf.DiagramDesigner/Helpers/WeakINPCEventHandler.cs
Normal file
37
AIStudio.Wpf.DiagramDesigner/Helpers/WeakINPCEventHandler.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner.Helpers
|
||||
{
|
||||
//[DebuggerNonUserCode]
|
||||
public sealed class WeakINPCEventHandler
|
||||
{
|
||||
private readonly WeakReference _targetReference;
|
||||
private readonly MethodInfo _method;
|
||||
|
||||
public WeakINPCEventHandler(PropertyChangedEventHandler callback)
|
||||
{
|
||||
_method = callback.Method;
|
||||
_targetReference = new WeakReference(callback.Target, true);
|
||||
}
|
||||
|
||||
//[DebuggerNonUserCode]
|
||||
public void Handler(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var target = _targetReference.Target;
|
||||
if (target != null)
|
||||
{
|
||||
var callback = (Action<object, PropertyChangedEventArgs>)Delegate.CreateDelegate(typeof(Action<object, PropertyChangedEventArgs>), target, _method, true);
|
||||
if (callback != null)
|
||||
{
|
||||
callback(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
AIStudio.Wpf.DiagramDesigner/Images/FormatPainter.cur
Normal file
BIN
AIStudio.Wpf.DiagramDesigner/Images/FormatPainter.cur
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
AIStudio.Wpf.DiagramDesigner/Images/Gifs/car_chase.gif
Normal file
BIN
AIStudio.Wpf.DiagramDesigner/Images/Gifs/car_chase.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 MiB |
BIN
AIStudio.Wpf.DiagramDesigner/Images/file.png
Normal file
BIN
AIStudio.Wpf.DiagramDesigner/Images/file.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
369
AIStudio.Wpf.DiagramDesigner/Messenger/Mediator.cs
Normal file
369
AIStudio.Wpf.DiagramDesigner/Messenger/Mediator.cs
Normal file
@@ -0,0 +1,369 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
#region WeakAction Inner Class
|
||||
/// <summary>
|
||||
/// This class creates a weak delegate of form Action(Of Object)
|
||||
/// </summary>
|
||||
public class WeakAction
|
||||
{
|
||||
#region Data
|
||||
private readonly WeakReference _target;
|
||||
private readonly Type _ownerType;
|
||||
private readonly Type _actionType;
|
||||
private readonly string _methodName;
|
||||
#endregion
|
||||
|
||||
#region Public Properties/Methods
|
||||
public WeakAction(object target, Type actionType, MethodBase mi)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
Debug.Assert(mi.IsStatic);
|
||||
_ownerType = mi.DeclaringType;
|
||||
}
|
||||
else
|
||||
_target = new WeakReference(target);
|
||||
_methodName = mi.Name;
|
||||
_actionType = actionType;
|
||||
}
|
||||
|
||||
public Type ActionType
|
||||
{
|
||||
get { return _actionType; }
|
||||
}
|
||||
|
||||
public bool HasBeenCollected
|
||||
{
|
||||
get
|
||||
{
|
||||
return (_ownerType == null && (_target == null || !_target.IsAlive));
|
||||
}
|
||||
}
|
||||
|
||||
public Delegate GetMethod()
|
||||
{
|
||||
if (_ownerType != null)
|
||||
{
|
||||
return Delegate.CreateDelegate(_actionType, _ownerType, _methodName);
|
||||
}
|
||||
|
||||
if (_target != null && _target.IsAlive)
|
||||
{
|
||||
object target = _target.Target;
|
||||
if (target != null)
|
||||
return Delegate.CreateDelegate(_actionType, target, _methodName);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This class creates a simple Mediator which loosely connects different objects together.
|
||||
/// The message handlers are organized using string-based message keys and are held in a WeakReference
|
||||
/// collection.
|
||||
/// </summary>
|
||||
public class Mediator
|
||||
{
|
||||
|
||||
|
||||
#region Data
|
||||
static readonly Mediator instance = new Mediator();
|
||||
static readonly object syncLock = new object();
|
||||
private readonly Dictionary<object, List<WeakAction>> _registeredHandlers =
|
||||
new Dictionary<object, List<WeakAction>>();
|
||||
#endregion
|
||||
|
||||
#region Ctor
|
||||
static Mediator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private Mediator()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Performs the actual registration of a target
|
||||
/// </summary>
|
||||
/// <param name="key">Key to store in dictionary</param>
|
||||
/// <param name="actionType">Delegate type</param>
|
||||
/// <param name="handler">Method</param>
|
||||
private void RegisterHandler(object key, Type actionType, Delegate handler)
|
||||
{
|
||||
var action = new WeakAction(handler.Target, actionType, handler.Method);
|
||||
|
||||
lock (_registeredHandlers)
|
||||
{
|
||||
List<WeakAction> wr;
|
||||
if (_registeredHandlers.TryGetValue(key, out wr))
|
||||
{
|
||||
if (wr.Count > 0)
|
||||
{
|
||||
WeakAction wa = wr[0];
|
||||
if (wa.ActionType != actionType &&
|
||||
!wa.ActionType.IsAssignableFrom(actionType))
|
||||
throw new ArgumentException("Invalid key passed to RegisterHandler - existing handler has incompatible parameter type");
|
||||
}
|
||||
|
||||
wr.Add(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
wr = new List<WeakAction> { action };
|
||||
_registeredHandlers.Add(key, wr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the unregistration from a target
|
||||
/// </summary>
|
||||
/// <param name="key">Key to store in dictionary</param>
|
||||
/// <param name="actionType">Delegate type</param>
|
||||
/// <param name="handler">Method</param>
|
||||
private void UnregisterHandler(object key, Type actionType, Delegate handler)
|
||||
{
|
||||
lock (_registeredHandlers)
|
||||
{
|
||||
List<WeakAction> wr;
|
||||
if (_registeredHandlers.TryGetValue(key, out wr))
|
||||
{
|
||||
wr.RemoveAll(wa => handler == wa.GetMethod() && actionType == wa.ActionType);
|
||||
|
||||
if (wr.Count == 0)
|
||||
_registeredHandlers.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method broadcasts a message to all message targets for a given
|
||||
/// message key and passes a parameter.
|
||||
/// </summary>
|
||||
/// <param name="key">Message key</param>
|
||||
/// <param name="message">Message parameter</param>
|
||||
/// <returns>True/False if any handlers were invoked.</returns>
|
||||
private bool NotifyColleagues(object key, object message)
|
||||
{
|
||||
List<WeakAction> wr;
|
||||
List<WeakAction> wrCopy = new List<WeakAction>();
|
||||
lock (_registeredHandlers)
|
||||
{
|
||||
if (!_registeredHandlers.TryGetValue(key, out wr))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
foreach (var weakRe in wr)
|
||||
{
|
||||
wrCopy.Add(weakRe);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach (var cb in wrCopy)
|
||||
{
|
||||
Delegate action = cb.GetMethod();
|
||||
|
||||
if (action != null)
|
||||
action.DynamicInvoke(message);
|
||||
}
|
||||
|
||||
lock (_registeredHandlers)
|
||||
{
|
||||
wr.RemoveAll(wa => wa.HasBeenCollected);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Properties/Methods
|
||||
|
||||
/// <summary>
|
||||
/// Singleton Instance
|
||||
/// </summary>
|
||||
public static Mediator Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This registers a Type with the mediator. Any methods decorated with <seealso cref="MediatorMessageSinkAttribute"/> will be
|
||||
/// registered as target method handlers for the given message key.
|
||||
/// </summary>
|
||||
/// <param name="view">Object to register</param>
|
||||
public void Register(object view)
|
||||
{
|
||||
// Look at all instance/static methods on this object type.
|
||||
foreach (var mi in view.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
|
||||
{
|
||||
// See if we have a target attribute - if so, register the method as a handler.
|
||||
foreach (var att in mi.GetCustomAttributes(typeof(MediatorMessageSinkAttribute), true))
|
||||
{
|
||||
var mha = (MediatorMessageSinkAttribute)att;
|
||||
var pi = mi.GetParameters();
|
||||
if (pi.Length != 1)
|
||||
throw new InvalidCastException("Cannot cast " + mi.Name + " to Action<T> delegate type.");
|
||||
|
||||
Type actionType = typeof(Action<>).MakeGenericType(pi[0].ParameterType);
|
||||
object key = (mha.MessageKey) ?? actionType;
|
||||
|
||||
if (mi.IsStatic)
|
||||
RegisterHandler(key, actionType, Delegate.CreateDelegate(actionType, mi));
|
||||
else
|
||||
RegisterHandler(key, actionType, Delegate.CreateDelegate(actionType, view, mi.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method unregisters a type from the message mediator.
|
||||
/// </summary>
|
||||
/// <param name="view">Object to unregister</param>
|
||||
public void Unregister(object view)
|
||||
{
|
||||
foreach (var mi in view.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
|
||||
{
|
||||
foreach (var att in mi.GetCustomAttributes(typeof(MediatorMessageSinkAttribute), true))
|
||||
{
|
||||
var mha = (MediatorMessageSinkAttribute)att;
|
||||
var pi = mi.GetParameters();
|
||||
if (pi.Length != 1)
|
||||
throw new InvalidCastException("Cannot cast " + mi.Name + " to Action<T> delegate type.");
|
||||
|
||||
Type actionType = typeof(Action<>).MakeGenericType(pi[0].ParameterType);
|
||||
object key = (mha.MessageKey) ?? actionType;
|
||||
|
||||
if (mi.IsStatic)
|
||||
UnregisterHandler(key, actionType, Delegate.CreateDelegate(actionType, mi));
|
||||
else
|
||||
UnregisterHandler(key, actionType, Delegate.CreateDelegate(actionType, view, mi.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This registers a specific method as a message handler for a specific type.
|
||||
/// </summary>
|
||||
/// <param name="key">Message key</param>
|
||||
/// <param name="handler">Handler method</param>
|
||||
public void RegisterHandler<T>(string key, Action<T> handler)
|
||||
{
|
||||
RegisterHandler(key, handler.GetType(), handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This registers a specific method as a message handler for a specific type.
|
||||
/// </summary>
|
||||
/// <param name="handler">Handler method</param>
|
||||
public void RegisterHandler<T>(Action<T> handler)
|
||||
{
|
||||
RegisterHandler(typeof(Action<T>), handler.GetType(), handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This unregisters a method as a handler.
|
||||
/// </summary>
|
||||
/// <param name="key">Message key</param>
|
||||
/// <param name="handler">Handler</param>
|
||||
public void UnregisterHandler<T>(string key, Action<T> handler)
|
||||
{
|
||||
UnregisterHandler(key, handler.GetType(), handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This unregisters a method as a handler for a specific type
|
||||
/// </summary>
|
||||
/// <param name="handler">Handler</param>
|
||||
public void UnregisterHandler<T>(Action<T> handler)
|
||||
{
|
||||
UnregisterHandler(typeof(Action<T>), handler.GetType(), handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method broadcasts a message to all message targets for a given
|
||||
/// message key and passes a parameter.
|
||||
/// </summary>
|
||||
/// <param name="key">Message key</param>
|
||||
/// <param name="message">Message parameter</param>
|
||||
/// <returns>True/False if any handlers were invoked.</returns>
|
||||
public bool NotifyColleagues<T>(string key, T message)
|
||||
{
|
||||
return NotifyColleagues((object)key, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method broadcasts a message to all message targets for a given parameter type.
|
||||
/// If a derived type is passed, any handlers for interfaces or base types will also be
|
||||
/// invoked.
|
||||
/// </summary>
|
||||
/// <param name="message">Message parameter</param>
|
||||
/// <returns>True/False if any handlers were invoked.</returns>
|
||||
public bool NotifyColleagues<T>(T message)
|
||||
{
|
||||
Type actionType = typeof(Action<>).MakeGenericType(typeof(T));
|
||||
var keyList = from key in _registeredHandlers.Keys
|
||||
where key is Type && ((Type)key).IsAssignableFrom(actionType)
|
||||
select key;
|
||||
bool rc = false;
|
||||
foreach (var key in keyList)
|
||||
rc |= NotifyColleagues(key, message);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method broadcasts a message to all message targets for a given
|
||||
/// message key and passes a parameter. The message targets are all called
|
||||
/// asynchronously and any resulting exceptions are ignored.
|
||||
/// </summary>
|
||||
/// <param name="key">Message key</param>
|
||||
/// <param name="message">Message parameter</param>
|
||||
public void NotifyColleaguesAsync<T>(string key, T message)
|
||||
{
|
||||
Func<string, T, bool> smaFunc = NotifyColleagues;
|
||||
smaFunc.BeginInvoke(key, message, ia =>
|
||||
{
|
||||
try { smaFunc.EndInvoke(ia); }
|
||||
catch { }
|
||||
}, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method broadcasts a message to all message targets for a given parameter type.
|
||||
/// If a derived type is passed, any handlers for interfaces or base types will also be
|
||||
/// invoked. The message targets are all called asynchronously and any resulting exceptions
|
||||
/// are ignored.
|
||||
/// </summary>
|
||||
/// <param name="message">Message parameter</param>
|
||||
public void NotifyColleaguesAsync<T>(T message)
|
||||
{
|
||||
Func<T, bool> smaFunc = NotifyColleagues;
|
||||
smaFunc.BeginInvoke(message, ia =>
|
||||
{
|
||||
try { smaFunc.EndInvoke(ia); }
|
||||
catch { }
|
||||
}, null);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
/// <summary>
|
||||
/// This attribute allows a method to be targeted as a recipient for a message.
|
||||
/// It requires that the Type is registered with the MessageMediator through the
|
||||
/// <seealso cref="MessageMediator.Register"/> method
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class MediatorMessageSinkAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Message key
|
||||
/// </summary>
|
||||
public object MessageKey { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public MediatorMessageSinkAttribute()
|
||||
{
|
||||
MessageKey = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that takes a message key
|
||||
/// </summary>
|
||||
/// <param name="messageKey">Message Key</param>
|
||||
public MediatorMessageSinkAttribute(string messageKey)
|
||||
{
|
||||
MessageKey = messageKey;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
108
AIStudio.Wpf.DiagramDesigner/Models/ConnectionItem.cs
Normal file
108
AIStudio.Wpf.DiagramDesigner/Models/ConnectionItem.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
[Serializable]
|
||||
[XmlInclude(typeof(ConnectionItem))]
|
||||
public class ConnectionItem : SelectableDesignerItemBase
|
||||
{
|
||||
public ConnectionItem()
|
||||
{
|
||||
|
||||
}
|
||||
//public ConnectionItem(Guid id, Guid sourceId, ConnectorOrientation sourceOrientation, Type sourceType, double sourceXRatio, double sourceYRatio, bool sourceInnerPoint,
|
||||
// Guid sinkId, ConnectorOrientation sinkOrientation, Type sinkType, double sinkXRatio, double sinkYRatio, bool sinkInnerPoint,
|
||||
// int zIndex, bool isGroup, Guid parentId, DrawMode vectorLineDrawMode, ColorViewModel colorViewModel, FontViewModel fontViewModel) : base(id, zIndex, isGroup, parentId, colorViewModel, fontViewModel)
|
||||
//{
|
||||
// this.SourceId = sourceId;
|
||||
// this.SourceOrientation = sourceOrientation;
|
||||
// this.SourceType = sourceType;
|
||||
// this.SourceTypeName = sourceType.FullName;
|
||||
// this.SourceXRatio = sourceXRatio;
|
||||
// this.SourceYRatio = sourceYRatio;
|
||||
// this.SourceInnerPoint = sourceInnerPoint;
|
||||
|
||||
// this.SinkId = sinkId;
|
||||
// this.SinkOrientation = sinkOrientation;
|
||||
// this.SinkType = sinkType;
|
||||
// this.SinkTypeName = sinkType.FullName;
|
||||
// this.SinkXRatio = sinkXRatio;
|
||||
// this.SinkYRatio = sinkYRatio;
|
||||
// this.SinkInnerPoint = sinkInnerPoint;
|
||||
// this.VectorLineDrawMode = vectorLineDrawMode;
|
||||
//}
|
||||
|
||||
public ConnectionItem(Guid sourceId, ConnectorOrientation sourceOrientation, Type sourceType, double sourceXRatio, double sourceYRatio, bool sourceInnerPoint,
|
||||
Guid sinkId, ConnectorOrientation sinkOrientation, Type sinkType, double sinkXRatio, double sinkYRatio, bool sinkInnerPoint, ConnectorViewModel viewmodel) : base(viewmodel)
|
||||
{
|
||||
this.SourceId = sourceId;
|
||||
this.SourceOrientation = sourceOrientation;
|
||||
this.SourceType = sourceType;
|
||||
this.SourceTypeName = sourceType.FullName;
|
||||
this.SourceXRatio = sourceXRatio;
|
||||
this.SourceYRatio = sourceYRatio;
|
||||
this.SourceInnerPoint = sourceInnerPoint;
|
||||
|
||||
this.SinkId = sinkId;
|
||||
this.SinkOrientation = sinkOrientation;
|
||||
this.SinkType = sinkType;
|
||||
this.SinkTypeName = sinkType.FullName;
|
||||
this.SinkXRatio = sinkXRatio;
|
||||
this.SinkYRatio = sinkYRatio;
|
||||
this.SinkInnerPoint = sinkInnerPoint;
|
||||
this.VectorLineDrawMode = viewmodel.VectorLineDrawMode;
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public Guid SourceId { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public ConnectorOrientation SourceOrientation { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public Type SourceType { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public string SourceTypeName { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double SourceXRatio { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double SourceYRatio { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public bool SourceInnerPoint { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public Guid SinkId { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public ConnectorOrientation SinkOrientation { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public Type SinkType { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public string SinkTypeName { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double SinkXRatio { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double SinkYRatio { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public bool SinkInnerPoint { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public DrawMode VectorLineDrawMode { get; set; }
|
||||
}
|
||||
}
|
||||
23
AIStudio.Wpf.DiagramDesigner/Models/ConnectorItem.cs
Normal file
23
AIStudio.Wpf.DiagramDesigner/Models/ConnectorItem.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ConnectorItem
|
||||
{
|
||||
public Guid ParentId { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
public double XRatio { get; set; }
|
||||
public double YRatio { get; set; }
|
||||
public double ConnectorWidth { get; set; }
|
||||
public double ConnectorHeight { get; set; }
|
||||
public ConnectorOrientation Orientation { get; set; }
|
||||
public bool IsInnerPoint { get; set; }
|
||||
public ValueTypePoint ValueTypePoint { get; set; }
|
||||
public double ConnectorValue { get; set; }
|
||||
}
|
||||
}
|
||||
72
AIStudio.Wpf.DiagramDesigner/Models/DesignerItemBase.cs
Normal file
72
AIStudio.Wpf.DiagramDesigner/Models/DesignerItemBase.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
[Serializable]
|
||||
[XmlInclude(typeof(DesignerItemBase))]
|
||||
public class DesignerItemBase : SelectableDesignerItemBase
|
||||
{
|
||||
public DesignerItemBase()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public DesignerItemBase(DesignerItemViewModelBase viewmodel, string reserve = null) : base(viewmodel)
|
||||
{
|
||||
this.Left = viewmodel.Left;
|
||||
this.Top = viewmodel.Top;
|
||||
this.Angle = viewmodel.Angle;
|
||||
this.ScaleX = viewmodel.ScaleX;
|
||||
this.ScaleY = viewmodel.ScaleY;
|
||||
this.ItemWidth = viewmodel.ItemWidth;
|
||||
this.ItemHeight = viewmodel.ItemHeight;
|
||||
this.Icon = viewmodel.Icon;
|
||||
this.ItemTypeName = viewmodel.GetType().FullName;
|
||||
this.Margin = viewmodel.Margin;
|
||||
this.Reserve = reserve;
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public double Left { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double Top { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double Angle { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double ScaleX { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double ScaleY { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double Margin { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double ItemWidth { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double ItemHeight { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public string Icon { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public string Reserve { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public string ItemTypeName { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
34
AIStudio.Wpf.DiagramDesigner/Models/ImageDesignerItem.cs
Normal file
34
AIStudio.Wpf.DiagramDesigner/Models/ImageDesignerItem.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ImageDesignerItem : DesignerItemBase
|
||||
{
|
||||
public ImageDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
public ImageDesignerItem(ImageItemViewModel item) : base(item)
|
||||
{
|
||||
Icon = item.Icon;
|
||||
Connectors = new List<ConnectorItem>();
|
||||
foreach (var fullyCreatedConnectorInfo in item.Connectors)
|
||||
{
|
||||
ConnectorItem connector = new ConnectorItem()
|
||||
{
|
||||
XRatio = fullyCreatedConnectorInfo.XRatio,
|
||||
YRatio = fullyCreatedConnectorInfo.YRatio,
|
||||
ConnectorWidth = fullyCreatedConnectorInfo.ConnectorWidth,
|
||||
ConnectorHeight = fullyCreatedConnectorInfo.ConnectorHeight,
|
||||
Orientation = fullyCreatedConnectorInfo.Orientation
|
||||
};
|
||||
Connectors.Add(connector);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlArray]
|
||||
public List<ConnectorItem> Connectors { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class LogicalGateDesignerItemBase : DesignerItemBase
|
||||
{
|
||||
public LogicalGateDesignerItemBase()
|
||||
{
|
||||
|
||||
}
|
||||
public LogicalGateDesignerItemBase(LogicalGateItemViewModelBase item) : base(item)
|
||||
{
|
||||
this.Connectors = new List<ConnectorItem>();
|
||||
foreach (var fullyCreatedConnectorInfo in item.Connectors)
|
||||
{
|
||||
ConnectorItem connector = new ConnectorItem()
|
||||
{
|
||||
XRatio = fullyCreatedConnectorInfo.XRatio,
|
||||
YRatio = fullyCreatedConnectorInfo.YRatio,
|
||||
ConnectorWidth = fullyCreatedConnectorInfo.ConnectorWidth,
|
||||
ConnectorHeight = fullyCreatedConnectorInfo.ConnectorHeight,
|
||||
Orientation = fullyCreatedConnectorInfo.Orientation,
|
||||
IsInnerPoint = fullyCreatedConnectorInfo.IsInnerPoint,
|
||||
ValueTypePoint = fullyCreatedConnectorInfo.ValueTypePoint,
|
||||
ConnectorValue = fullyCreatedConnectorInfo.ConnectorValue
|
||||
};
|
||||
this.Connectors.Add(connector);
|
||||
}
|
||||
this.OrderNumber = item.OrderNumber;
|
||||
this.LogicalType = item.LogicalType;
|
||||
this.Value = item.Value;
|
||||
this.IsEnabled = item.IsEnabled;
|
||||
}
|
||||
|
||||
[XmlArray]
|
||||
public List<ConnectorItem> Connectors { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public int OrderNumber { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double Value { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public LogicalType LogicalType { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public bool IsEnabled { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
51
AIStudio.Wpf.DiagramDesigner/Models/MediaDesignerItem.cs
Normal file
51
AIStudio.Wpf.DiagramDesigner/Models/MediaDesignerItem.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class MediaDesignerItem : DesignerItemBase
|
||||
{
|
||||
public MediaDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MediaDesignerItem(GifImageItemViewModel item) : base(item)
|
||||
{
|
||||
Connectors = new List<ConnectorItem>();
|
||||
foreach (var fullyCreatedConnectorInfo in item.Connectors)
|
||||
{
|
||||
ConnectorItem connector = new ConnectorItem()
|
||||
{
|
||||
XRatio = fullyCreatedConnectorInfo.XRatio,
|
||||
YRatio = fullyCreatedConnectorInfo.YRatio,
|
||||
ConnectorWidth = fullyCreatedConnectorInfo.ConnectorWidth,
|
||||
ConnectorHeight = fullyCreatedConnectorInfo.ConnectorHeight,
|
||||
Orientation = fullyCreatedConnectorInfo.Orientation
|
||||
};
|
||||
Connectors.Add(connector);
|
||||
}
|
||||
}
|
||||
|
||||
public MediaDesignerItem(MediaItemViewModel item) : base(item)
|
||||
{
|
||||
Connectors = new List<ConnectorItem>();
|
||||
foreach (var fullyCreatedConnectorInfo in item.Connectors)
|
||||
{
|
||||
ConnectorItem connector = new ConnectorItem()
|
||||
{
|
||||
XRatio = fullyCreatedConnectorInfo.XRatio,
|
||||
YRatio = fullyCreatedConnectorInfo.YRatio,
|
||||
ConnectorWidth = fullyCreatedConnectorInfo.ConnectorWidth,
|
||||
ConnectorHeight = fullyCreatedConnectorInfo.ConnectorHeight,
|
||||
Orientation = fullyCreatedConnectorInfo.Orientation
|
||||
};
|
||||
Connectors.Add(connector);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlArray]
|
||||
public List<ConnectorItem> Connectors { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,496 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
|
||||
public abstract class SelectableDesignerItemBase
|
||||
{
|
||||
public SelectableDesignerItemBase()
|
||||
{
|
||||
ColorItem = new ColorItem() { LineColor = new ColorObjectItem(), FillColor = new ColorObjectItem() };
|
||||
FontItem = new FontItem();
|
||||
}
|
||||
|
||||
//public SelectableDesignerItemBase(Guid id, int zIndex, bool isGroup, Guid parentId, IColorViewModel colorViewModel, IFontViewModel fontViewModel)
|
||||
//{
|
||||
// this.Id = id;
|
||||
// this.ZIndex = zIndex;
|
||||
// this.IsGroup = isGroup;
|
||||
// this.ParentId = parentId;
|
||||
|
||||
|
||||
// ColorItem = CopyHelper.Mapper<ColorItem>(colorViewModel);
|
||||
// FontItem = CopyHelper.Mapper<FontItem, IFontViewModel>(fontViewModel);
|
||||
//}
|
||||
|
||||
public SelectableDesignerItemBase(SelectableDesignerItemViewModelBase viewmodel)
|
||||
{
|
||||
this.Id = viewmodel.Id;
|
||||
this.ZIndex = viewmodel.ZIndex;
|
||||
this.IsGroup = viewmodel.IsGroup;
|
||||
this.ParentId = viewmodel.ParentId;
|
||||
this.Text = viewmodel.Text;
|
||||
|
||||
ColorItem = CopyHelper.Mapper<ColorItem>(viewmodel.ColorViewModel);
|
||||
FontItem = CopyHelper.Mapper<FontItem, IFontViewModel>(viewmodel.FontViewModel);
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public int ZIndex { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public bool IsGroup { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public Guid ParentId { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public string Text { get; set; }
|
||||
|
||||
[XmlElement]
|
||||
public ColorItem ColorItem { get; set; }
|
||||
|
||||
[XmlElement]
|
||||
public FontItem FontItem { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ColorItem : IColorViewModel
|
||||
{
|
||||
[XmlIgnore]
|
||||
public IColorObject LineColor { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlElement("LineColor")]
|
||||
public ColorObjectItem XmlLineColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return LineColor as ColorObjectItem;
|
||||
}
|
||||
set
|
||||
{
|
||||
LineColor = value;
|
||||
}
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public IColorObject FillColor { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlElement("FillColor")]
|
||||
public ColorObjectItem XmlFillColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return FillColor as ColorObjectItem;
|
||||
}
|
||||
set
|
||||
{
|
||||
FillColor = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[XmlIgnore]
|
||||
public Color ShadowColor { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlElement("ShadowColor")]
|
||||
public string XmlShadowColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return SerializeHelper.SerializeColor(ShadowColor);
|
||||
}
|
||||
set
|
||||
{
|
||||
ShadowColor = SerializeHelper.DeserializeColor(value);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public double LineWidth { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public ArrowPathStyle LeftArrowPathStyle { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public ArrowPathStyle RightArrowPathStyle { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public ArrowSizeStyle LeftArrowSizeStyle { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public ArrowSizeStyle RightArrowSizeStyle { get; set; }
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
}
|
||||
|
||||
[XmlInclude(typeof(FontItem))]
|
||||
public class FontItem : IFontViewModel
|
||||
{
|
||||
[XmlIgnore]
|
||||
public FontWeight FontWeight { get; set; }
|
||||
[XmlIgnore]
|
||||
public FontStyle FontStyle { get; set; }
|
||||
[XmlIgnore]
|
||||
public FontStretch FontStretch { get; set; }
|
||||
[XmlAttribute]
|
||||
public bool Underline { get; set; }
|
||||
[XmlAttribute]
|
||||
public bool Strikethrough { get; set; }
|
||||
[XmlAttribute]
|
||||
public bool OverLine { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public Color FontColor { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlElement("FontColor")]
|
||||
public string XmlFontColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return SerializeHelper.SerializeColor(FontColor);
|
||||
}
|
||||
set
|
||||
{
|
||||
FontColor = SerializeHelper.DeserializeColor(value);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public string FontFamily { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public double FontSize { get; set; }
|
||||
|
||||
|
||||
[XmlIgnore]
|
||||
public System.Drawing.Font FontObject
|
||||
{
|
||||
get
|
||||
{
|
||||
var xmlFontStyle = System.Drawing.FontStyle.Regular;
|
||||
if (FontStyle == FontStyles.Italic)
|
||||
{
|
||||
xmlFontStyle |= System.Drawing.FontStyle.Italic;
|
||||
}
|
||||
if (FontWeight == FontWeights.Bold)
|
||||
{
|
||||
xmlFontStyle |= System.Drawing.FontStyle.Bold;
|
||||
}
|
||||
return new System.Drawing.Font(FontFamily, (float)FontSize, xmlFontStyle);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
FontFamily = value.FontFamily.Name;
|
||||
FontSize = value.Size;
|
||||
var xmlFontStyle = value.Style;
|
||||
if ((xmlFontStyle & System.Drawing.FontStyle.Italic) == System.Drawing.FontStyle.Italic)
|
||||
{
|
||||
FontStyle = FontStyles.Italic;
|
||||
}
|
||||
else
|
||||
{
|
||||
FontStyle = FontStyles.Normal;
|
||||
}
|
||||
if ((xmlFontStyle & System.Drawing.FontStyle.Bold) == System.Drawing.FontStyle.Bold)
|
||||
{
|
||||
FontWeight = FontWeights.Bold;
|
||||
}
|
||||
else
|
||||
{
|
||||
FontWeight = FontWeights.Regular;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlElement("FontObject")]
|
||||
public XmlFont XmlFontObject
|
||||
{
|
||||
get
|
||||
{
|
||||
return SerializeHelper.SerializeFont(FontObject);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
FontObject = SerializeHelper.DeserializeFont(value);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public Color TextEffectColor { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlElement("TextEffectColor")]
|
||||
public string XmlTextEffectColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return SerializeHelper.SerializeColor(TextEffectColor);
|
||||
}
|
||||
set
|
||||
{
|
||||
TextEffectColor = SerializeHelper.DeserializeColor(value);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public Color HighlightColor { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlElement("HighlightColor")]
|
||||
public string XmlHighlightColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return SerializeHelper.SerializeColor(HighlightColor);
|
||||
}
|
||||
set
|
||||
{
|
||||
HighlightColor = SerializeHelper.DeserializeColor(value);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public FontCase FontCase { get; set; }
|
||||
[XmlAttribute]
|
||||
public HorizontalAlignment HorizontalAlignment { get; set; }
|
||||
[XmlAttribute]
|
||||
public VerticalAlignment VerticalAlignment { get; set; }
|
||||
[XmlAttribute]
|
||||
public double LineHeight { get; set; }
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
}
|
||||
|
||||
public class SerializeHelper
|
||||
{
|
||||
public static string SerializeColor(Color color)
|
||||
{
|
||||
return string.Format("{0}:{1}:{2}:{3}", color.A, color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
public static Color DeserializeColor(string color)
|
||||
{
|
||||
byte a, r, g, b;
|
||||
string[] pieces = color.Split(new char[] { ':' });
|
||||
a = byte.Parse(pieces[0]);
|
||||
r = byte.Parse(pieces[1]);
|
||||
g = byte.Parse(pieces[2]);
|
||||
b = byte.Parse(pieces[3]);
|
||||
return Color.FromArgb(a, r, g, b);
|
||||
}
|
||||
|
||||
public static GradientStop DeserializeGradientStop(string str)
|
||||
{
|
||||
var strList = str.Split('-');
|
||||
return new GradientStop(DeserializeColor(strList[0]), double.Parse(strList[1]));
|
||||
}
|
||||
|
||||
public static string SerializeColorList(IEnumerable<Color> colors)
|
||||
{
|
||||
return string.Join("-", colors.Select(color => string.Format("{0}:{1}:{2}:{3}", color.A, color.R, color.G, color.B)));
|
||||
}
|
||||
|
||||
public static List<Color> DeserializeColorList(string colorstring)
|
||||
{
|
||||
List<Color> colorlist = new List<Color>();
|
||||
var colors = colorstring.Split('-');
|
||||
foreach (var color in colors)
|
||||
{
|
||||
byte a, r, g, b;
|
||||
string[] pieces = color.Split(new char[] { ':' });
|
||||
a = byte.Parse(pieces[0]);
|
||||
r = byte.Parse(pieces[1]);
|
||||
g = byte.Parse(pieces[2]);
|
||||
b = byte.Parse(pieces[3]);
|
||||
colorlist.Add(Color.FromArgb(a, r, g, b));
|
||||
}
|
||||
return colorlist;
|
||||
}
|
||||
|
||||
public static XmlFont SerializeFont(System.Drawing.Font font)
|
||||
{
|
||||
return new XmlFont(font);
|
||||
}
|
||||
|
||||
public static System.Drawing.Font DeserializeFont(XmlFont font)
|
||||
{
|
||||
return font.ToFont();
|
||||
}
|
||||
|
||||
public static string SerializePoint(Point point)
|
||||
{
|
||||
return string.Format("{0},{1}", point.X, point.Y);
|
||||
}
|
||||
|
||||
public static Point DeserializePoint(string point)
|
||||
{
|
||||
string[] pieces = point.Split(new char[] { ',' });
|
||||
return new Point(double.Parse(pieces[0]), double.Parse(pieces[1]));
|
||||
}
|
||||
|
||||
public static string SerializeSize(Size size)
|
||||
{
|
||||
return string.Format("{0},{1}", size.Width, size.Height);
|
||||
}
|
||||
|
||||
public static Size DeserializeSize(string size)
|
||||
{
|
||||
string[] pieces = size.Split(new char[] { ',' });
|
||||
return new Size(double.Parse(pieces[0]), double.Parse(pieces[1]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public struct XmlFont
|
||||
{
|
||||
public string FontFamily;
|
||||
public System.Drawing.GraphicsUnit GraphicsUnit;
|
||||
public float Size;
|
||||
public System.Drawing.FontStyle Style;
|
||||
|
||||
public XmlFont(System.Drawing.Font f)
|
||||
{
|
||||
FontFamily = f.FontFamily.Name;
|
||||
GraphicsUnit = f.Unit;
|
||||
Size = f.Size;
|
||||
Style = f.Style;
|
||||
}
|
||||
|
||||
public System.Drawing.Font ToFont()
|
||||
{
|
||||
return new System.Drawing.Font(FontFamily, Size, Style, GraphicsUnit);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ColorObjectItem : IColorObject
|
||||
{
|
||||
|
||||
[XmlAttribute]
|
||||
public BrushType BrushType { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public Color Color { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlElement("FillColor")]
|
||||
public string XmlFillColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return SerializeHelper.SerializeColor(Color);
|
||||
}
|
||||
set
|
||||
{
|
||||
Color = SerializeHelper.DeserializeColor(value);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public ObservableCollection<GradientStop> GradientStop { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlArray("GradientStop")]
|
||||
public List<string> XmlGradientStop
|
||||
{
|
||||
get
|
||||
{
|
||||
return GradientStop?.Select(p => SerializeHelper.SerializeColor(p.Color) + "-" + p.Offset).ToList();
|
||||
}
|
||||
set
|
||||
{
|
||||
GradientStop = new ObservableCollection<GradientStop>(value?.Select(p => SerializeHelper.DeserializeGradientStop(p)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[XmlIgnore]
|
||||
public IEnumerable<double> Offset { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlArray("Offset")]
|
||||
public List<double> XmlOffset
|
||||
{
|
||||
get
|
||||
{
|
||||
return Offset?.ToList();
|
||||
}
|
||||
set
|
||||
{
|
||||
Offset = value;
|
||||
}
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public string Image { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public int SubType { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public Point StartPoint { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlAttribute("StartPoint")]
|
||||
public string XmlStartPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return SerializeHelper.SerializePoint(StartPoint);
|
||||
}
|
||||
set
|
||||
{
|
||||
StartPoint = SerializeHelper.DeserializePoint(value);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlIgnore]
|
||||
public Point EndPoint { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[XmlAttribute("EndPoint")]
|
||||
public string XmlEndPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return SerializeHelper.SerializePoint(EndPoint);
|
||||
}
|
||||
set
|
||||
{
|
||||
EndPoint = SerializeHelper.DeserializePoint(value);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlAttribute]
|
||||
public double Opacity { get; set; }
|
||||
[XmlAttribute]
|
||||
public LinearOrientation LinearOrientation { get; set; }
|
||||
[XmlAttribute]
|
||||
public RadialOrientation RadialOrientation { get; set; }
|
||||
[XmlAttribute]
|
||||
public int Angle { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
23
AIStudio.Wpf.DiagramDesigner/Models/TextDesignerItem.cs
Normal file
23
AIStudio.Wpf.DiagramDesigner/Models/TextDesignerItem.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using AIStudio.Wpf.DiagramDesigner;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class TextDesignerItem : DesignerItemBase
|
||||
{
|
||||
public TextDesignerItem()
|
||||
{
|
||||
|
||||
}
|
||||
public TextDesignerItem(TextDesignerItemViewModel item) : base(item)
|
||||
{
|
||||
this.Text = item.Text;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
25
AIStudio.Wpf.DiagramDesigner/Paths/ArrowPathData.cs
Normal file
25
AIStudio.Wpf.DiagramDesigner/Paths/ArrowPathData.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class ArrowPathData
|
||||
{
|
||||
public static readonly List<string> Arrow = new List<string>()
|
||||
{
|
||||
"",
|
||||
"M0,10 L5,0 10,10 z",
|
||||
"M832 664c0 10.752-3.968 20.096-11.904 28.096C812.096 700.096 802.752 704 792 704l-560 0c-10.816 0-20.16-3.904-28.096-11.904C195.904 684.096 192 674.752 192 664s3.904-20.096 11.904-28.096l280-280C491.84 348.032 501.184 344 512 344c10.752 0 20.096 3.968 28.096 11.904l280 280C828.032 643.904 832 653.248 832 664z",
|
||||
"M691.626667 682.666667H332.373333a75.093333 75.093333 0 0 1-67.84-42.666667 89.6 89.6 0 0 1 11.093334-94.293333l179.626666-217.6a75.093333 75.093333 0 0 1 113.493334 0l179.626666 217.6A89.6 89.6 0 0 1 759.466667 640a75.093333 75.093333 0 0 1-67.84 42.666667z",
|
||||
"M171.64288 701.41952a47.18592 47.18592 0 0 1 4.11648-57.344l276.70528-310.12864a79.60576 79.60576 0 0 1 119.05024 0l276.72576 310.10816a47.18592 47.18592 0 0 1 3.072 58.83904c-11.30496 15.29856-32.768 18.45248-47.9232 7.04512l-255.488-192.14336a59.65824 59.65824 0 0 0-71.80288 0l-255.488 192.14336a34.05824 34.05824 0 0 1-48.9472-8.54016z",
|
||||
"M119.466667 827.733333L512 435.2l392.533333 392.533333 119.466667-119.466666-512-512-512 512z",
|
||||
"M957.44 772.813L509.952 391.066 66.97 772.608 0 694.886 509.542 256 1024 694.784z",
|
||||
"M828.47744 660.7872a81.7152 81.7152 0 0 1-62.48448 28.89728 81.73568 81.73568 0 0 1-52.98176-19.47648l-172.46208-146.45248-172.4416 146.45248a81.94048 81.94048 0 0 1-106.06592-124.86656l225.4848-191.50848a81.89952 81.89952 0 0 1 106.06592 0l225.4848 191.50848a81.85856 81.85856 0 0 1 9.40032 115.44576z",
|
||||
"M256.917333 780.288c-40.725333 40.405333-106.645333 40.512-147.264 0.192l-36.373333-36.096a103.36 103.36 0 0 1 0.085333-146.944l350.421334-347.754667a125.290667 125.290667 0 0 1 176.490666 0l350.4 347.754667a103.466667 103.466667 0 0 1 0.085334 146.944l-36.352 36.096c-40.682667 40.362667-106.56 40.192-147.264-0.192L512.021333 527.104 256.917333 780.288z m225.066667-343.594667a42.666667 42.666667 0 0 1 60.096 0l285.184 283.029334a19.328 19.328 0 0 0 27.029333 0.192l36.352-36.096a18.154667 18.154667 0 0 0-0.064-25.813334L540.16 310.250667a39.957333 39.957333 0 0 0-56.256 0L133.482667 658.005333a18.026667 18.026667 0 0 0-0.085334 25.813334l36.373334 36.096a19.349333 19.349333 0 0 0 27.029333-0.192L481.962667 436.693333z",
|
||||
"M67.969 562.046c0 23.955 19.441 43.396 43.396 43.396 10.773 0 20.33-4.346 27.937-10.86l0.425 0.425 2.235-2.235c0.044-0.044 0.067-0.063 0.112-0.106l358.336-358.338c6.256-6.239 16.377-6.239 22.61 0l360.685 360.679 0.658-0.659c7.647 6.685 17.356 11.093 28.3 11.093 23.935 0 43.374-19.441 43.374-43.396 0-15.289-8.389-28.084-20.355-35.812-0.724-1.344-0.576-2.983-1.705-4.112l-410.958-410.948c-6.234-6.244-16.354-6.244-22.61 0l-410.95 410.949c-1.279 1.279-1.172 3.108-1.916 4.641-11.522 7.794-19.571 20.336-19.571 35.283zM67.969 874.116c0 23.955 19.441 43.394 43.396 43.394 10.773 0 20.33-4.342 27.937-10.855l0.425 0.425 2.235-2.235c0.044-0.045 0.067-0.065 0.112-0.109l358.336-358.339c6.256-6.239 16.377-6.239 22.61 0l360.685 360.684 0.658-0.66c7.647 6.685 17.356 11.091 28.3 11.091 23.935 0 43.374-19.439 43.374-43.394 0-15.289-8.389-28.087-20.355-35.815-0.724-1.341-0.576-2.98-1.705-4.109l-410.958-410.951c-6.234-6.239-16.354-6.239-22.61 0l-410.95 410.953c-1.279 1.277-1.172 3.107-1.916 4.641-11.522 7.794-19.571 20.334-19.571 35.282z",
|
||||
"M548.010667 233.088c-15.658667-24.576-56.32-24.576-72.021334 0l-298.666666 469.333333a42.794667 42.794667 0 0 0-1.408 43.477334c7.509333 13.610667 21.845333 22.101333 37.418666 22.101333h597.333334a42.709333 42.709333 0 0 0 36.010666-65.621333l-298.666666-469.290667zM291.029333 682.666667L512 335.488 732.970667 682.666667H291.029333z",
|
||||
"M512.1 511.2m-447.3 0a447.3 447.3 0 1 0 894.6 0 447.3 447.3 0 1 0-894.6 0Z",
|
||||
};
|
||||
}
|
||||
}
|
||||
36
AIStudio.Wpf.DiagramDesigner/Paths/StrokeDashArray.cs
Normal file
36
AIStudio.Wpf.DiagramDesigner/Paths/StrokeDashArray.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class StrokeDashArray
|
||||
{
|
||||
public static readonly List<DoubleCollection> Dash = new List<DoubleCollection>
|
||||
{
|
||||
new DoubleCollection() { 1, 0 },
|
||||
new DoubleCollection() { 8, 4 },
|
||||
new DoubleCollection() { 1, 4 },
|
||||
new DoubleCollection() { 8, 4, 2, 4 },
|
||||
new DoubleCollection() { 8, 4, 2, 4, 2, 4 },
|
||||
new DoubleCollection() { 8, 4, 8, 4, 2, 4 },
|
||||
new DoubleCollection() { 18, 4, 4, 4 },
|
||||
new DoubleCollection() { 18, 4, 4, 4, 4, 4 },
|
||||
new DoubleCollection() { 4, 4 },
|
||||
new DoubleCollection() { 2, 2 },
|
||||
new DoubleCollection() { 5, 2, 2, 2 },
|
||||
new DoubleCollection() { 5, 2, 2, 2, 2, 2 },
|
||||
new DoubleCollection() { 10, 4, 4, 4 },
|
||||
new DoubleCollection() { 10, 4, 4, 4, 4, 4 },
|
||||
new DoubleCollection() { 16, 8 },
|
||||
new DoubleCollection() { 2, 8 },
|
||||
new DoubleCollection() { 16, 8, 2, 8 },
|
||||
new DoubleCollection() { 16, 8, 2, 8, 2, 8 },
|
||||
new DoubleCollection() { 16, 8, 16, 8, 2, 8 },
|
||||
new DoubleCollection() { 40, 8, 8, 8 },
|
||||
new DoubleCollection() { 40, 8, 8, 8, 8, 8 },
|
||||
new DoubleCollection() { 4, 2 },
|
||||
};
|
||||
}
|
||||
}
|
||||
16
AIStudio.Wpf.DiagramDesigner/Properties/AssemblyInfo.cs
Normal file
16
AIStudio.Wpf.DiagramDesigner/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
[assembly: XmlnsDefinition("https://astudio.github.io/diagram", "AIStudio.Wpf.DiagramDesigner")]
|
||||
[assembly: XmlnsDefinition("https://astudio.github.io/diagram", "AIStudio.Wpf.DiagramDesigner.Controls")]
|
||||
|
||||
[assembly: XmlnsPrefix("https://astudio.github.io/diagram", "dd")]
|
||||
@@ -0,0 +1,69 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:AIStudio.Wpf.DiagramDesigner"
|
||||
xmlns:c="clr-namespace:AIStudio.Wpf.DiagramDesigner.Controls">
|
||||
|
||||
|
||||
<!-- Connector Style -->
|
||||
<Style TargetType="{x:Type s:Connector}">
|
||||
<Setter Property="Width"
|
||||
Value="8" />
|
||||
<Setter Property="Height"
|
||||
Value="8" />
|
||||
<Setter Property="Cursor"
|
||||
Value="Cross" />
|
||||
<Setter Property="SnapsToDevicePixels"
|
||||
Value="true" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type s:Connector}">
|
||||
<Grid>
|
||||
<!-- transparent extra space makes connector easier to hit -->
|
||||
<Rectangle Fill="Transparent"
|
||||
Margin="-2" />
|
||||
<Rectangle Fill="Lavender"
|
||||
StrokeThickness="1"
|
||||
Stroke="#AA000080" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- ConnectorDecoratorTemplate Default Template -->
|
||||
<ControlTemplate x:Key="ConnectorDecoratorTemplate"
|
||||
TargetType="{x:Type Control}">
|
||||
<Grid Margin="-5">
|
||||
<s:Connector x:Name="Left"
|
||||
Orientation="Left"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left" />
|
||||
<s:Connector x:Name="Top"
|
||||
Orientation="Top"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Center" />
|
||||
<s:Connector x:Name="Right"
|
||||
Orientation="Right"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right" />
|
||||
<s:Connector x:Name="Bottom"
|
||||
Orientation="Bottom"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
|
||||
<!-- DragThumb Default Template -->
|
||||
<Style TargetType="{x:Type c:DragThumb}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type c:DragThumb}">
|
||||
<Rectangle Fill="Transparent" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
|
||||
</ResourceDictionary>
|
||||
117
AIStudio.Wpf.DiagramDesigner/Resources/Styles/Expander.xaml
Normal file
117
AIStudio.Wpf.DiagramDesigner/Resources/Styles/Expander.xaml
Normal file
@@ -0,0 +1,117 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Shared.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<!-- SimpleStyles: Expander -->
|
||||
|
||||
<ControlTemplate x:Key="ExpanderToggleButton" TargetType="ToggleButton">
|
||||
<Border
|
||||
Name="Border"
|
||||
CornerRadius="2,0,0,0"
|
||||
Background="Transparent"
|
||||
BorderBrush="{StaticResource NormalBorderBrush}"
|
||||
BorderThickness="0,0,0,0">
|
||||
<Path
|
||||
Name="Arrow"
|
||||
Fill="{StaticResource GlyphBrush}"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M 0 0 L 4 4 L 8 0 Z"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
|
||||
<Setter TargetName="Border" Property="Background"
|
||||
Value="{StaticResource DarkBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="true">
|
||||
<Setter TargetName="Border" Property="Background"
|
||||
Value="{StaticResource PressedBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsChecked" Value="true">
|
||||
<Setter TargetName="Arrow" Property="Data"
|
||||
Value="M 0 4 L 4 0 L 8 4 Z" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Border" Property="Background"
|
||||
Value="{StaticResource DisabledBackgroundBrush}" />
|
||||
<Setter TargetName="Border" Property="BorderBrush"
|
||||
Value="{StaticResource DisabledBorderBrush}" />
|
||||
<Setter Property="Foreground"
|
||||
Value="{StaticResource DisabledForegroundBrush}"/>
|
||||
<Setter TargetName="Arrow" Property="Fill"
|
||||
Value="{StaticResource DisabledForegroundBrush}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style TargetType="Expander">
|
||||
<Setter Property="FontFamily" Value="SegoeUI"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Foreground" Value="#4C4C4C"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Expander">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Name="ContentRow" Height="0"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border
|
||||
Name="Border"
|
||||
Grid.Row="0"
|
||||
Background="{StaticResource LightBrush}"
|
||||
BorderBrush="{StaticResource NormalBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="2,2,0,0" >
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ToggleButton
|
||||
IsChecked="{Binding Path=IsExpanded,Mode=TwoWay,
|
||||
RelativeSource={RelativeSource TemplatedParent}}"
|
||||
OverridesDefaultStyle="True"
|
||||
Template="{StaticResource ExpanderToggleButton}"
|
||||
Background="{StaticResource NormalBrush}" />
|
||||
<ContentPresenter
|
||||
Grid.Column="1"
|
||||
Margin="4"
|
||||
ContentSource="Header"
|
||||
RecognizesAccessKey="True" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
Name="Content"
|
||||
Grid.Row="1"
|
||||
Background="{StaticResource WindowBackgroundBrush}"
|
||||
BorderBrush="{StaticResource SolidBorderBrush}"
|
||||
BorderThickness="1,0,1,1"
|
||||
CornerRadius="0,0,2,2" >
|
||||
<ContentPresenter Margin="4" />
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsExpanded" Value="True">
|
||||
<Setter TargetName="ContentRow" Property="Height"
|
||||
Value="{Binding ElementName=Content,Path=DesiredHeight}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Border" Property="Background"
|
||||
Value="{StaticResource DisabledBackgroundBrush}" />
|
||||
<Setter TargetName="Border" Property="BorderBrush"
|
||||
Value="{StaticResource DisabledBorderBrush}" />
|
||||
<Setter Property="Foreground"
|
||||
Value="{StaticResource DisabledForegroundBrush}"/>
|
||||
</Trigger>
|
||||
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
47
AIStudio.Wpf.DiagramDesigner/Resources/Styles/GroupBox.xaml
Normal file
47
AIStudio.Wpf.DiagramDesigner/Resources/Styles/GroupBox.xaml
Normal file
@@ -0,0 +1,47 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Shared.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<!-- SimpleStyles: GroupBox -->
|
||||
<Style TargetType="GroupBox">
|
||||
<Setter Property="FontFamily" Value="SegoeUI"/>
|
||||
<Setter Property="FontSize" Value="12"/>
|
||||
<Setter Property="Foreground" Value="#4C4C4C"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="GroupBox">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border
|
||||
Grid.Row="0"
|
||||
Background="{StaticResource LightBrush}"
|
||||
BorderBrush="{StaticResource NormalBorderBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="2,2,0,0" >
|
||||
<ContentPresenter
|
||||
Margin="4"
|
||||
ContentSource="Header"
|
||||
RecognizesAccessKey="True" />
|
||||
</Border>
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{StaticResource SolidBorderBrush}"
|
||||
BorderThickness="1,0,1,1"
|
||||
CornerRadius="0,0,2,2" >
|
||||
<ContentPresenter
|
||||
Margin="4" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
186
AIStudio.Wpf.DiagramDesigner/Resources/Styles/ScrollBar.xaml
Normal file
186
AIStudio.Wpf.DiagramDesigner/Resources/Styles/ScrollBar.xaml
Normal file
@@ -0,0 +1,186 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Shared.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style x:Key="ScrollBarLineButton" TargetType="{x:Type RepeatButton}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
<Setter Property="OverridesDefaultStyle" Value="true"/>
|
||||
<Setter Property="Focusable" Value="false"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type RepeatButton}">
|
||||
<Border
|
||||
Name="Border"
|
||||
Margin="1"
|
||||
CornerRadius="2"
|
||||
Background="{StaticResource NormalBrush}"
|
||||
BorderBrush="{StaticResource NormalBorderBrush}"
|
||||
BorderThickness="1">
|
||||
<Path
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Fill="{StaticResource GlyphBrush}"
|
||||
Data="{Binding Path=Content,RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsPressed" Value="true">
|
||||
<Setter TargetName="Border" Property="Background" Value="{StaticResource PressedBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="false">
|
||||
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ScrollBarPageButton" TargetType="{x:Type RepeatButton}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
<Setter Property="OverridesDefaultStyle" Value="true"/>
|
||||
<Setter Property="IsTabStop" Value="false"/>
|
||||
<Setter Property="Focusable" Value="false"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type RepeatButton}">
|
||||
<Border Background="Transparent" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ScrollBarThumb" TargetType="{x:Type Thumb}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
<Setter Property="OverridesDefaultStyle" Value="true"/>
|
||||
<Setter Property="IsTabStop" Value="false"/>
|
||||
<Setter Property="Focusable" Value="false"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||
<Border
|
||||
CornerRadius="2"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="1" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||
<Grid >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition MaxHeight="18"/>
|
||||
<RowDefinition Height="0.00001*"/>
|
||||
<RowDefinition MaxHeight="18"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border
|
||||
Grid.RowSpan="3"
|
||||
CornerRadius="2"
|
||||
Background="#F0F0F0" />
|
||||
<RepeatButton
|
||||
Grid.Row="0"
|
||||
Style="{StaticResource ScrollBarLineButton}"
|
||||
Height="18"
|
||||
Command="ScrollBar.LineUpCommand"
|
||||
Content="M 0 4 L 8 4 L 4 0 Z" />
|
||||
<Track
|
||||
Name="PART_Track"
|
||||
Grid.Row="1"
|
||||
IsDirectionReversed="true">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton
|
||||
Style="{StaticResource ScrollBarPageButton}"
|
||||
Command="ScrollBar.PageUpCommand" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb
|
||||
Style="{StaticResource ScrollBarThumb}"
|
||||
Margin="1,0,1,0"
|
||||
Background="{StaticResource HorizontalNormalBrush}"
|
||||
BorderBrush="{StaticResource HorizontalNormalBorderBrush}" />
|
||||
</Track.Thumb>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton
|
||||
Style="{StaticResource ScrollBarPageButton}"
|
||||
Command="ScrollBar.PageDownCommand" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
</Track>
|
||||
<RepeatButton
|
||||
Grid.Row="3"
|
||||
Style="{StaticResource ScrollBarLineButton}"
|
||||
Height="18"
|
||||
Command="ScrollBar.LineDownCommand"
|
||||
Content="M 0 0 L 4 4 L 8 0 Z"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<ControlTemplate x:Key="HorizontalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||
<Grid >
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition MaxWidth="18"/>
|
||||
<ColumnDefinition Width="0.00001*"/>
|
||||
<ColumnDefinition MaxWidth="18"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Border
|
||||
Grid.ColumnSpan="3"
|
||||
CornerRadius="2"
|
||||
Background="#F0F0F0" />
|
||||
<RepeatButton
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource ScrollBarLineButton}"
|
||||
Width="18"
|
||||
Command="ScrollBar.LineLeftCommand"
|
||||
Content="M 4 0 L 4 8 L 0 4 Z" />
|
||||
<Track
|
||||
Name="PART_Track"
|
||||
Grid.Column="1"
|
||||
IsDirectionReversed="False">
|
||||
<Track.DecreaseRepeatButton>
|
||||
<RepeatButton
|
||||
Style="{StaticResource ScrollBarPageButton}"
|
||||
Command="ScrollBar.PageLeftCommand" />
|
||||
</Track.DecreaseRepeatButton>
|
||||
<Track.Thumb>
|
||||
<Thumb
|
||||
Style="{StaticResource ScrollBarThumb}"
|
||||
Margin="0,1,0,1"
|
||||
Background="{StaticResource NormalBrush}"
|
||||
BorderBrush="{StaticResource NormalBorderBrush}" />
|
||||
</Track.Thumb>
|
||||
<Track.IncreaseRepeatButton>
|
||||
<RepeatButton
|
||||
Style="{StaticResource ScrollBarPageButton}"
|
||||
Command="ScrollBar.PageRightCommand" />
|
||||
</Track.IncreaseRepeatButton>
|
||||
</Track>
|
||||
<RepeatButton
|
||||
Grid.Column="3"
|
||||
Style="{StaticResource ScrollBarLineButton}"
|
||||
Width="18"
|
||||
Command="ScrollBar.LineRightCommand"
|
||||
Content="M 0 0 L 4 4 L 0 8 Z"/>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
||||
<Style x:Key="{x:Type ScrollBar}" TargetType="{x:Type ScrollBar}">
|
||||
<Setter Property="SnapsToDevicePixels" Value="True"/>
|
||||
<Setter Property="OverridesDefaultStyle" Value="true"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Orientation" Value="Horizontal">
|
||||
<Setter Property="Width" Value="Auto"/>
|
||||
<Setter Property="Height" Value="18" />
|
||||
<Setter Property="Template" Value="{StaticResource HorizontalScrollBar}" />
|
||||
</Trigger>
|
||||
<Trigger Property="Orientation" Value="Vertical">
|
||||
<Setter Property="Width" Value="18"/>
|
||||
<Setter Property="Height" Value="Auto" />
|
||||
<Setter Property="Template" Value="{StaticResource VerticalScrollBar}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,43 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
|
||||
|
||||
<!-- SimpleStyles: ScrollViewer -->
|
||||
|
||||
<Style x:Key="LeftScrollViewer" TargetType="{x:Type ScrollViewer}">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ScrollViewer}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ScrollContentPresenter Grid.Column="1"/>
|
||||
|
||||
<ScrollBar Name="PART_VerticalScrollBar"
|
||||
Value="{TemplateBinding VerticalOffset}"
|
||||
Maximum="{TemplateBinding ScrollableHeight}"
|
||||
ViewportSize="{TemplateBinding ViewportHeight}"
|
||||
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
|
||||
<ScrollBar Name="PART_HorizontalScrollBar"
|
||||
Orientation="Horizontal"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Value="{TemplateBinding HorizontalOffset}"
|
||||
Maximum="{TemplateBinding ScrollableWidth}"
|
||||
ViewportSize="{TemplateBinding ViewportWidth}"
|
||||
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
|
||||
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
118
AIStudio.Wpf.DiagramDesigner/Resources/Styles/Shared.xaml
Normal file
118
AIStudio.Wpf.DiagramDesigner/Resources/Styles/Shared.xaml
Normal file
@@ -0,0 +1,118 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<!-- Fill Brushes -->
|
||||
|
||||
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#FFF" Offset="0.0"/>
|
||||
<GradientStop Color="#CCC" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<LinearGradientBrush x:Key="HorizontalNormalBrush" StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#FFF" Offset="0.0"/>
|
||||
<GradientStop Color="#CCC" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<LinearGradientBrush x:Key="LightBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#FFF" Offset="0.0"/>
|
||||
<GradientStop Color="#EEE" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<LinearGradientBrush x:Key="HorizontalLightBrush" StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#FFF" Offset="0.0"/>
|
||||
<GradientStop Color="#EEE" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<LinearGradientBrush x:Key="DarkBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#FFF" Offset="0.0"/>
|
||||
<GradientStop Color="#AAA" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#BBB" Offset="0.0"/>
|
||||
<GradientStop Color="#EEE" Offset="0.1"/>
|
||||
<GradientStop Color="#EEE" Offset="0.9"/>
|
||||
<GradientStop Color="#FFF" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
|
||||
|
||||
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
|
||||
|
||||
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
|
||||
|
||||
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
|
||||
|
||||
<!-- Border Brushes -->
|
||||
|
||||
<LinearGradientBrush x:Key="NormalBorderBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#CCC" Offset="0.0"/>
|
||||
<GradientStop Color="#444" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<LinearGradientBrush x:Key="HorizontalNormalBorderBrush" StartPoint="0,0" EndPoint="1,0">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#CCC" Offset="0.0"/>
|
||||
<GradientStop Color="#444" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<LinearGradientBrush x:Key="DefaultedBorderBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#777" Offset="0.0"/>
|
||||
<GradientStop Color="#000" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<LinearGradientBrush x:Key="PressedBorderBrush" StartPoint="0,0" EndPoint="0,1">
|
||||
<GradientBrush.GradientStops>
|
||||
<GradientStopCollection>
|
||||
<GradientStop Color="#444" Offset="0.0"/>
|
||||
<GradientStop Color="#888" Offset="1.0"/>
|
||||
</GradientStopCollection>
|
||||
</GradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
|
||||
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" />
|
||||
|
||||
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
|
||||
|
||||
<SolidColorBrush x:Key="LightBorderBrush" Color="#AAA" />
|
||||
|
||||
<SolidColorBrush x:Key="GlyphBrush" Color="#444" />
|
||||
|
||||
<SolidColorBrush x:Key="LightColorBrush" Color="#DDD" />
|
||||
|
||||
</ResourceDictionary>
|
||||
38
AIStudio.Wpf.DiagramDesigner/Resources/Styles/ToolTip.xaml
Normal file
38
AIStudio.Wpf.DiagramDesigner/Resources/Styles/ToolTip.xaml
Normal file
@@ -0,0 +1,38 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Shared.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<!-- SimpleStyles: ToolTip -->
|
||||
<Style x:Key="{x:Type ToolTip}" TargetType="ToolTip">
|
||||
<Setter Property="OverridesDefaultStyle" Value="true"/>
|
||||
<Setter Property="HasDropShadow" Value="True"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ToolTip">
|
||||
<Border Name="Border"
|
||||
Background="{StaticResource LightBrush}"
|
||||
BorderBrush="{StaticResource SolidBorderBrush}"
|
||||
BorderThickness="1"
|
||||
Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}">
|
||||
<ContentPresenter
|
||||
Margin="4"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="HasDropShadow" Value="true">
|
||||
<Setter TargetName="Border" Property="CornerRadius" Value="4"/>
|
||||
<Setter TargetName="Border" Property="SnapsToDevicePixels" Value="true"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
245
AIStudio.Wpf.DiagramDesigner/Resources/Styles/ZoomBox.xaml
Normal file
245
AIStudio.Wpf.DiagramDesigner/Resources/Styles/ZoomBox.xaml
Normal file
@@ -0,0 +1,245 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:s="clr-namespace:AIStudio.Wpf.DiagramDesigner">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Shared.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<Style TargetType="{x:Type s:ZoomBox}">
|
||||
|
||||
<Style.Resources>
|
||||
|
||||
<VisualBrush x:Key="AlphaBrush"
|
||||
Stretch="None"
|
||||
TileMode="Tile"
|
||||
ViewportUnits="Absolute"
|
||||
Viewport="0,0,8,8">
|
||||
<VisualBrush.Visual>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="4" />
|
||||
<ColumnDefinition Width="4" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="4" />
|
||||
<RowDefinition Height="4" />
|
||||
</Grid.RowDefinitions>
|
||||
<Rectangle Fill="#EEE"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0" />
|
||||
<Rectangle Fill="#AAA"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1" />
|
||||
<Rectangle Fill="#AAA"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0" />
|
||||
<Rectangle Fill="#EEE"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1" />
|
||||
</Grid>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
|
||||
<Style x:Key="ToggleButtonStyle"
|
||||
TargetType="ToggleButton">
|
||||
<Setter Property="SnapsToDevicePixels"
|
||||
Value="true" />
|
||||
<Setter Property="OverridesDefaultStyle"
|
||||
Value="true" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ToggleButton">
|
||||
<Border x:Name="Border"
|
||||
Background="{StaticResource NormalBrush}">
|
||||
<ContentPresenter />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver"
|
||||
Value="true">
|
||||
<Setter TargetName="Border"
|
||||
Property="Background"
|
||||
Value="{StaticResource DarkBrush}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="Expander">
|
||||
<Setter Property="SnapsToDevicePixels"
|
||||
Value="true" />
|
||||
<Setter Property="OverridesDefaultStyle"
|
||||
Value="true" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Expander">
|
||||
<DockPanel>
|
||||
<ToggleButton Style="{StaticResource ToggleButtonStyle}"
|
||||
DockPanel.Dock="Top"
|
||||
IsChecked="{Binding Path=IsExpanded,Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
HorizontalContentAlignment="Left"
|
||||
VerticalContentAlignment="Center">
|
||||
<ToggleButton.Content>
|
||||
<Grid Margin="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Path Grid.Column="0"
|
||||
SnapsToDevicePixels="True"
|
||||
Name="Arrow"
|
||||
Fill="{TemplateBinding Foreground}"
|
||||
Stroke="{TemplateBinding Foreground}"
|
||||
StrokeThickness="0.5"
|
||||
RenderTransformOrigin="0.5,0.5"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Data="M 0 0 L 0 8 L 5 4 Z">
|
||||
<Path.RenderTransform>
|
||||
<RotateTransform Angle="0" />
|
||||
</Path.RenderTransform>
|
||||
</Path>
|
||||
<ContentPresenter Grid.Column="1"
|
||||
Name="HeaderContent"
|
||||
ContentSource="Header" />
|
||||
</Grid>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<Border Name="Content">
|
||||
<Border.LayoutTransform>
|
||||
<ScaleTransform ScaleY="0" />
|
||||
</Border.LayoutTransform>
|
||||
<ContentPresenter Content="{TemplateBinding Content}" />
|
||||
</Border>
|
||||
</DockPanel>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="Expander.IsExpanded"
|
||||
Value="True">
|
||||
<Trigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="Content"
|
||||
Storyboard.TargetProperty="LayoutTransform.ScaleY"
|
||||
To="1"
|
||||
Duration="0:0:0.3" />
|
||||
<DoubleAnimation Storyboard.TargetName="Content"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="1"
|
||||
Duration="0:0:0.3" />
|
||||
<DoubleAnimation Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(FrameworkElement.RenderTransform).(RotateTransform.Angle)"
|
||||
Duration="0:0:0.2"
|
||||
To="90"
|
||||
DecelerationRatio="1" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.EnterActions>
|
||||
<Trigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="Content"
|
||||
Storyboard.TargetProperty="LayoutTransform.ScaleY"
|
||||
To="0"
|
||||
Duration="0:0:0.3" />
|
||||
<DoubleAnimation Storyboard.TargetName="Content"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0"
|
||||
Duration="0:0:0.3" />
|
||||
<DoubleAnimation Storyboard.TargetName="Arrow"
|
||||
Storyboard.TargetProperty="(FrameworkElement.RenderTransform).(RotateTransform.Angle)"
|
||||
Duration="0:0:0.2"
|
||||
AccelerationRatio="1" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.ExitActions>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</Style.Resources>
|
||||
|
||||
<Setter Property="SnapsToDevicePixels"
|
||||
Value="true" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type s:ZoomBox}">
|
||||
<Border CornerRadius="1"
|
||||
BorderThickness="1"
|
||||
Background="#EEE"
|
||||
BorderBrush="DimGray">
|
||||
<Expander IsExpanded="True"
|
||||
Background="Transparent">
|
||||
<Border BorderBrush="DimGray"
|
||||
BorderThickness="0,1,0,0"
|
||||
Padding="0"
|
||||
Height="180">
|
||||
<Grid>
|
||||
<Canvas Margin="5"
|
||||
Name="PART_ZoomCanvas">
|
||||
<Canvas.Background>
|
||||
<VisualBrush Stretch="Uniform"
|
||||
Visual="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ScrollViewer.Content}" />
|
||||
</Canvas.Background>
|
||||
<Thumb Name="PART_ZoomThumb"
|
||||
Cursor="SizeAll">
|
||||
<Thumb.Style>
|
||||
<Style TargetType="Thumb">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Thumb">
|
||||
<Rectangle StrokeThickness="1"
|
||||
Stroke="Black"
|
||||
Fill="Transparent" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Thumb.Style>
|
||||
</Thumb>
|
||||
</Canvas>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Expander.Header>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Slider Name="PART_ZoomSlider"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0"
|
||||
Ticks="25,50,75,100,125,150,200,300,400,500"
|
||||
Minimum="25"
|
||||
Maximum="500"
|
||||
SmallChange="25"
|
||||
LargeChange="25"
|
||||
Value="100"
|
||||
MinWidth="104"
|
||||
MinHeight="21"
|
||||
IsSnapToTickEnabled="True"
|
||||
IsMoveToPointEnabled="False" />
|
||||
|
||||
<TextBlock Text="{Binding ElementName=PART_ZoomSlider, Path=Value}"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,14,0" />
|
||||
<TextBlock Text="%"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="1,0,2,0" />
|
||||
</Grid>
|
||||
</Expander.Header>
|
||||
</Expander>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
public class DesignerItemsControlItemStyleSelector : StyleSelector
|
||||
{
|
||||
static DesignerItemsControlItemStyleSelector()
|
||||
{
|
||||
Instance = new DesignerItemsControlItemStyleSelector();
|
||||
}
|
||||
|
||||
public static DesignerItemsControlItemStyleSelector Instance
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
|
||||
public override Style SelectStyle(object item, DependencyObject container)
|
||||
{
|
||||
ItemsControl itemsControl = ItemsControl.ItemsControlFromItemContainer(container);
|
||||
if (itemsControl == null)
|
||||
throw new InvalidOperationException("DesignerItemsControlItemStyleSelector : Could not find ItemsControl");
|
||||
|
||||
if (item is GifImageItemViewModel)
|
||||
{
|
||||
return (Style)itemsControl.FindResource("gifimageItemStyle");
|
||||
}
|
||||
|
||||
if (item is LinkPointDesignerItemViewModel)
|
||||
{
|
||||
return (Style)itemsControl.FindResource("linkpointItemStyle");
|
||||
}
|
||||
|
||||
if (item is PointDesignerItemViewModel)
|
||||
{
|
||||
return (Style)itemsControl.FindResource("pointItemStyle");
|
||||
}
|
||||
|
||||
if (item is LogicalGateItemViewModelBase)
|
||||
{
|
||||
return (Style)itemsControl.FindResource("logicalItemStyle");
|
||||
}
|
||||
|
||||
if (item is DesignerItemViewModelBase)
|
||||
{
|
||||
|
||||
return (Style)itemsControl.FindResource("designerItemStyle");
|
||||
}
|
||||
|
||||
if (item is ConnectorViewModel)
|
||||
{
|
||||
return (Style)itemsControl.FindResource("connectorItemStyle");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
204
AIStudio.Wpf.DiagramDesigner/Themes/Generic.xaml
Normal file
204
AIStudio.Wpf.DiagramDesigner/Themes/Generic.xaml
Normal file
@@ -0,0 +1,204 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="clr-namespace:AIStudio.Wpf.DiagramDesigner"
|
||||
xmlns:c="clr-namespace:AIStudio.Wpf.DiagramDesigner.Controls"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com" >
|
||||
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
||||
<s:ColorBrushConverter x:Key="ColorBrushConverter" />
|
||||
<s:ConectorOrientationConverter x:Key="ConectorOrientationConverter" />
|
||||
<s:ConectorValueConverter x:Key="ConectorValueConverter"/>
|
||||
<s:ArrowPathConverter x:Key="ArrowPathConverter"/>
|
||||
<s:ArrowSizeConverter x:Key="ArrowSizeConverter"/>
|
||||
<s:LineDashConverter x:Key="LineDashConverter"/>
|
||||
<s:ClipConverter x:Key="ClipConverter"/>
|
||||
|
||||
<DataTemplate DataType="{x:Type s:TextDesignerItemViewModel}">
|
||||
<Grid >
|
||||
<Border Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" IsHitTestVisible="False"/>
|
||||
<Grid Margin="5">
|
||||
<s:TextControl s:ControlAttachProperty.Watermark="{Binding Watermark}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type s:ShapeDesignerItemViewModel}">
|
||||
<Grid IsHitTestVisible="False" Background="White">
|
||||
<Grid.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="显示点" IsCheckable="True" IsChecked="{Binding ShowConnectors}" />
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
<Control x:Name="control" />
|
||||
</Grid>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding DrawMode}" Value="Line">
|
||||
<Setter TargetName="control" Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Line X1="{Binding ConnectionPoints[0].X}" Y1="{Binding ConnectionPoints[0].Y}"
|
||||
X2="{Binding ConnectionPoints[1].X}" Y2="{Binding ConnectionPoints[1].Y}"
|
||||
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
StrokeThickness="{Binding ColorViewModel.LineWidth}"
|
||||
Stretch="Fill"></Line>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding DrawMode}" Value="Rectangle">
|
||||
<Setter TargetName="control" Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Rectangle
|
||||
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
StrokeThickness="{Binding ColorViewModel.LineWidth}"
|
||||
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
Stretch="Fill"></Rectangle>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding DrawMode}" Value="Ellipse">
|
||||
<Setter TargetName="control" Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Ellipse
|
||||
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
StrokeThickness="{Binding ColorViewModel.LineWidth}"
|
||||
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
Stretch="Fill"></Ellipse>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding DrawMode}" Value="Polyline">
|
||||
<Setter TargetName="control" Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Polyline
|
||||
Points="{Binding ConnectionPoints, Converter={x:Static s:ConnectionPathConverter.Instance}}"
|
||||
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
StrokeThickness="{Binding ColorViewModel.LineWidth}"
|
||||
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
FillRule="Nonzero"
|
||||
Stretch="Fill"></Polyline>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding DrawMode}" Value="Polygon">
|
||||
<Setter TargetName="control" Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Polygon
|
||||
Points="{Binding ConnectionPoints, Converter={x:Static s:ConnectionPathConverter.Instance}}"
|
||||
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
StrokeThickness="{Binding ColorViewModel.LineWidth}"
|
||||
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
FillRule="Nonzero"
|
||||
Stretch="Fill"></Polygon>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding DrawMode}" Value="DirectLine">
|
||||
<Setter TargetName="control" Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Polyline
|
||||
Points="{Binding ConnectionPoints, Converter={x:Static s:ConnectionPathConverter.Instance}}"
|
||||
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
StrokeThickness="{Binding ColorViewModel.LineWidth}"
|
||||
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
|
||||
FillRule="Nonzero"
|
||||
Stretch="Fill"></Polyline>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
|
||||
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type s:GroupDesignerItemViewModel}">
|
||||
<Grid IsHitTestVisible="{Binding IsHitTestVisible}">
|
||||
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type s:GifImageItemViewModel}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<Image Name="PART_Image_run" gif:ImageBehavior.AnimatedSource="{Binding Icon}" gif:ImageBehavior.AutoStart="True" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Visible"/>
|
||||
<Control x:Name="control" />
|
||||
</Grid>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding IsRunning}" Value="false">
|
||||
<Setter TargetName="PART_Image_run" Property="gif:ImageBehavior.AutoStart" Value="False" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type s:VideoItemViewModel}">
|
||||
<Grid IsHitTestVisible="False">
|
||||
<MediaElement x:Name="MediaPlayer" LoadedBehavior="Play" Source="{Binding Icon}" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Visible"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type s:ImageItemViewModel}">
|
||||
<Grid ToolTip="{Binding Icon}">
|
||||
<Grid IsHitTestVisible="False" ClipToBounds="True">
|
||||
<Image x:Name="image" Source="{Binding Icon}" Stretch="Fill"
|
||||
Margin="{Binding Object,Converter={StaticResource ClipConverter},ConverterParameter='Margin'}"
|
||||
Clip="{Binding Object,Converter={StaticResource ClipConverter},ConverterParameter='Clip'}">
|
||||
</Image>
|
||||
<Image x:Name="gif" gif:ImageBehavior.AnimatedSource="{Binding Icon}" gif:ImageBehavior.AutoStart="True" Visibility="Collapsed" Stretch="Fill"/>
|
||||
</Grid>
|
||||
<!-- PART_ResizeDecorator -->
|
||||
<Border x:Name="PART_ResizeDecorator" SnapsToDevicePixels="true" Margin="{Binding ResizeMargin,Mode=TwoWay}" Visibility="Collapsed">
|
||||
<Grid x:Name="Grid" Margin="-2">
|
||||
<c:BorderResizeThumb Height="5" Cursor="SizeAll" Margin="-3" ResizeMode="DragMargin" BorderBrush="Blue" BorderThickness="5" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
|
||||
<c:BorderResizeThumb Width="5" Cursor="SizeAll" Margin="-3" ResizeMode="DragMargin" BorderBrush="Blue" BorderThickness="5" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
|
||||
<c:BorderResizeThumb Width="5" Cursor="SizeAll" Margin="-3" ResizeMode="DragMargin" BorderBrush="Blue" BorderThickness="5" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
|
||||
<c:BorderResizeThumb Height="5" Cursor="SizeAll" Margin="-3" ResizeMode="DragMargin" BorderBrush="Blue" BorderThickness="5" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
|
||||
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNS" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Center"/>
|
||||
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeWE" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeWE" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNS" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
|
||||
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNWSE" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Left"/>
|
||||
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNESW" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Top" HorizontalAlignment="Right"/>
|
||||
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNESW" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
|
||||
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNWSE" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
|
||||
VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding Suffix}" Value=".gif">
|
||||
<Setter TargetName="gif" Property="Visibility" Value="Visible"/>
|
||||
<Setter TargetName="image" Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding ResizeMode}" Value="True">
|
||||
<Setter TargetName="PART_ResizeDecorator" Property="Visibility" Value="Visible"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Suffix}" Value=".txt">
|
||||
<Setter TargetName="image" Property="Source" Value="pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Images/file.png"/>
|
||||
<Setter TargetName="image" Property="Margin" Value="0"/>
|
||||
<Setter TargetName="image" Property="Clip" Value="{x:Null}"/>
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,14 @@
|
||||
<ItemsControl x:Class="AIStudio.Wpf.DiagramDesigner.ConnectorContainer"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:s="clr-namespace:AIStudio.Wpf.DiagramDesigner"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<Canvas x:Name="rootCanvas" Loaded="rootCanvas_Loaded"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
</ItemsControl>
|
||||
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace AIStudio.Wpf.DiagramDesigner
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ConnectorContainer.xaml
|
||||
/// </summary>
|
||||
public partial class ConnectorContainer : ItemsControl
|
||||
{
|
||||
private Canvas rootCanvas;
|
||||
public ConnectorContainer()
|
||||
{
|
||||
InitializeComponent();
|
||||
((INotifyCollectionChanged)Items).CollectionChanged += ConnectorContainer_CollectionChanged;
|
||||
}
|
||||
|
||||
void ConnectorContainer_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Action == NotifyCollectionChangedAction.Add)
|
||||
{
|
||||
foreach(var item in e.NewItems)
|
||||
{
|
||||
FullyCreatedConnectorInfo vm = item as FullyCreatedConnectorInfo;
|
||||
var connector = ItemContainerGenerator.ContainerFromItem(item) as ContentPresenter;
|
||||
|
||||
Canvas.SetLeft(connector, vm.DataItem.ItemWidth * vm.XRatio - vm.ConnectorWidth / 2);
|
||||
Canvas.SetTop(connector, vm.DataItem.ItemHeight * vm.YRatio - vm.ConnectorHeight / 2);
|
||||
}
|
||||
//SetConnectorLocation();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectorContainer_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
SetConnectorLocation();
|
||||
}
|
||||
|
||||
private void rootCanvas_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
rootCanvas = sender as Canvas;
|
||||
SetConnectorLocation();
|
||||
SizeChanged += ConnectorContainer_SizeChanged;
|
||||
}
|
||||
|
||||
private void SetConnectorLocation()
|
||||
{
|
||||
foreach (var connector in rootCanvas.Children.OfType<ContentPresenter>())
|
||||
{
|
||||
var vm = connector.DataContext as FullyCreatedConnectorInfo;
|
||||
if (vm != null)
|
||||
{
|
||||
Canvas.SetLeft(connector, vm.DataItem.ItemWidth * vm.XRatio - vm.ConnectorWidth / 2);
|
||||
Canvas.SetTop(connector, vm.DataItem.ItemHeight * vm.YRatio - vm.ConnectorHeight / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1018
AIStudio.Wpf.DiagramDesigner/UserControls/DiagramControl.xaml
Normal file
1018
AIStudio.Wpf.DiagramDesigner/UserControls/DiagramControl.xaml
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user