添加项目文件。

This commit is contained in:
akwkevin
2021-07-23 09:42:22 +08:00
commit f25a958797
2798 changed files with 352360 additions and 0 deletions

View 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 Util.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);
}
}
}
}
}
}
}

View File

@@ -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 Util.DiagramDesigner.Helpers;
namespace Util.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));
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
namespace Util.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;
}
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
namespace Util.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);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
[AttributeUsage(AttributeTargets.Property)]
public class CanDoAttribute : Attribute
{
}
}

View 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 Util.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,
}
}

View File

@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Util.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
}
}

View 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 Util.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;
}
}
}

View File

@@ -0,0 +1,470 @@
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 Util.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:,,,/Util.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));
_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));
_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));
}
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);
_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 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;
}
}
}

View File

@@ -0,0 +1,111 @@
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 Util.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;
}
}
}

View 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 Util.DiagramDesigner
{
public class PointConnector : Control
{
}
}

View File

@@ -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 Util.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);
}
}
}

View 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 Util.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
}
}

View 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 Util.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;
}
}
}

View 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 Util.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;
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Windows.Data;
namespace Util.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();
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Windows.Data;
namespace Util.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();
}
}
}

View File

@@ -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 Util.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();
}
}
}

View 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 Util.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();
}
}
}

View 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 Util.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();
}
}
}

View File

@@ -0,0 +1,32 @@
using Util.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 Util.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();
}
}
}

View File

@@ -0,0 +1,47 @@
using Util.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 Util.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();
}
}
}

View File

@@ -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 Util.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<Point> points = (List<Point>)value;
PointCollection pointCollection = new PointCollection();
if (points != null)
{
foreach (Point point in points)
{
pointCollection.Add(point);
}
}
return pointCollection;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,85 @@
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Util.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;
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Data;
namespace Util.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
}
}

View 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 Util.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();
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Windows.Data;
namespace Util.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();
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace Util.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();
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
public enum ArrowPathStyle
{
None,
Arrow1,
Arrow2,
Arrow3,
Arrow4,
Arrow5,
Arrow6,
Arrow7,
Arrow8,
Arrow9,
Arrow10,
Arrow11,
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Util.DiagramDesigner
{
public enum ArrowSizeStyle
{
[Description("非常小")]
VerySmall = 6,
[Description("小")]
Small = 8,
[Description("中")]
Middle = 10,
[Description("大")]
Large = 12,
[Description("特别大")]
ExtraLarge = 16,
[Description("巨大")]
Huge = 24,
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Util.DiagramDesigner
{
public enum BrushType
{
None,
SolidColorBrush,
LinearGradientBrush,
RadialGradientBrush,
ImageBrush,
VisualBrush,
DrawingBrush
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
public enum CellHorizontalAlignment
{
None,
Left,
Center,
Right
}
public enum CellVerticalAlignment
{
None,
Top,
Center,
Bottom
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
public enum ConnectorOrientation
{
None = 0,
Left = 1,
Top = 2,
Right = 3,
Bottom = 4
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
public enum CursorMode
{
Normal = 0,
Format = 1,
Move = 2,
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
public enum DiagramType
{
Normal,
FlowChart,
Logical
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
public enum DrawMode
{
Normal = 0,
Line = 1,
Rectangle = 2,
Ellipse = 3,
Polyline = 4,
Polygon = 5,
DirectLine = 6,
ConnectingLine = 10,
CornerConnectingLine = 11,
RadiusConnectingLine = 12,
Text = 20,
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
public enum FontCase
{
None,
Upper,
Lower,
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
public enum HorizontalVerticalAlignment
{
TopAlignLeft,
TopAlignCenter,
TopAlignRight,
TopAlignJustify,
CenterAlignLeft,
CenterAlignCenter,
CenterAlignRight,
CenterAlignJustify,
BottomAlignLeft,
BottomAlignCenter,
BottomAlignRight,
BottomAlignJustify,
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.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
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Util.DiagramDesigner
{
public enum LinearOrientation
{
[Description("左到右")]
LeftToRight,
[Description("左上到右下")]
LeftTopToRightBottom,
[Description("上到下")]
TopToBottom,
[Description("右上到左下")]
RightTopToLeftBottom,
[Description("右到左")]
RightToLeft,
[Description("右下到左上")]
RightBottomToLeftTop,
[Description("下到上")]
BottomToTop,
[Description("左下到右上")]
LeftBottomToRightTop
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Util.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,
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.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,
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Util.DiagramDesigner
{
public enum PageSizeOrientation
{
[Description("竖向")]
Vertical,
[Description("横向")]
Horizontal,
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Util.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,
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Util.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,
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace Util.DiagramDesigner
{
public enum RadialOrientation
{
[Description("中心")]
Center,
[Description("左上")]
LeftTop,
[Description("右上")]
RightTop,
[Description("右下")]
RightBottom,
[Description("左下")]
LeftBottom,
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.DiagramDesigner
{
public enum ValueTypePoint
{
Real = 0,
Int = 1,
Bool = 2,
}
}

View File

@@ -0,0 +1,626 @@
using System;
using System.Windows.Media;
namespace Util.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
}

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace Util.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);
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Util.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; }
}
}

View 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 Util.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
}
}

View File

@@ -0,0 +1,187 @@
using Microsoft.Xaml.Behaviors;
using System;
using System.Windows;
using System.Windows.Input;
namespace Util.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
}
}

View File

@@ -0,0 +1,184 @@
using Microsoft.Xaml.Behaviors;
using System;
using System.Windows;
using System.Windows.Input;
namespace Util.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
}
}

View File

@@ -0,0 +1,177 @@
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 Util.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()
{
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) 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);
}
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Util.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
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Util.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); } }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Util.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; }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.ComponentModel;
using System.Reflection;
namespace Util.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;
}
}
}

View 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 Util.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;
}
}
}

View 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 Util.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;
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Util.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 isInnerPoint = false);
}
}

View File

@@ -0,0 +1,693 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace Util.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);
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 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 (!isInnerPoint)
{
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;
}
}
}
}

View File

@@ -0,0 +1,69 @@
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 Util.DiagramDesigner
{
public class PointHelper
{
public static Point GetPointForConnector(FullyCreatedConnectorInfo connector)
{
Point point = new Point();
if (connector.IsInnerPoint)
{
switch (connector.Orientation)
{
case ConnectorOrientation.Top:
point = new Point(connector.DataItem.Left + connector.DataItem.ItemWidth * connector.XRatio + connector.ConnectorWidth / 2,
connector.DataItem.Top + connector.DataItem.ItemHeight * connector.YRatio);
break;
case ConnectorOrientation.Bottom:
point = new Point(connector.DataItem.Left + connector.DataItem.ItemWidth * connector.XRatio + connector.ConnectorWidth / 2,
connector.DataItem.Top + connector.DataItem.ItemHeight * connector.YRatio + connector.ConnectorHeight / 2); ;
break;
case ConnectorOrientation.Right:
point = new Point(connector.DataItem.Left + connector.DataItem.ItemWidth * connector.XRatio,
connector.DataItem.Top + connector.DataItem.ItemHeight * connector.YRatio + connector.ConnectorHeight / 2);
break;
case ConnectorOrientation.Left:
point = new Point(connector.DataItem.Left + connector.DataItem.ItemWidth * connector.XRatio,
connector.DataItem.Top + connector.DataItem.ItemHeight * connector.YRatio + connector.ConnectorHeight / 2);
break;
default:
point = new Point(connector.DataItem.Left + connector.DataItem.ItemWidth * connector.XRatio + connector.ConnectorWidth / 2,
connector.DataItem.Top + connector.DataItem.ItemHeight * connector.YRatio + connector.ConnectorHeight / 2);
break;
}
}
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;
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Util.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();
}
}
}

View 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 Util.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);
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -0,0 +1,369 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics;
namespace Util.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
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Util.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;
}
}
}

View File

@@ -0,0 +1,103 @@
using Util.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 Util.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, 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;
}
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;
}
[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; }
}
}

View File

@@ -0,0 +1,23 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Util.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; }
}
}

View File

@@ -0,0 +1,72 @@
using Util.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 Util.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; }
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Xml.Serialization;
namespace Util.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; }
}
}

View File

@@ -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 Util.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; }
}
}

View File

@@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.Xml.Serialization;
namespace Util.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; }
}
}

View File

@@ -0,0 +1,485 @@
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 Util.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 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; }
}
}

View File

@@ -0,0 +1,23 @@
using Util.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace Util.DiagramDesigner
{
public class TextDesignerItem : DesignerItemBase
{
public TextDesignerItem()
{
}
public TextDesignerItem(TextDesignerItemViewModel item) : base(item)
{
this.Text = item.Text;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Util.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",
};
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Media;
namespace Util.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 },
};
}
}

View 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", "Util.DiagramDesigner")]
[assembly: XmlnsDefinition("https://astudio.github.io/diagram", "Util.DiagramDesigner.Controls")]
[assembly: XmlnsPrefix("https://astudio.github.io/diagram", "dd")]

View File

@@ -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:Util.DiagramDesigner"
xmlns:c="clr-namespace:Util.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>

View 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>

View 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>

View 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>

View File

@@ -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>

View 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>

View 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>

View 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:Util.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>

View File

@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
namespace Util.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;
}
}
}

View 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:Util.DiagramDesigner"
xmlns:c="clr-namespace:Util.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:,,,/Util.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>

View File

@@ -0,0 +1,14 @@
<ItemsControl x:Class="Util.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:Util.DiagramDesigner"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas x:Name="rootCanvas" Loaded="rootCanvas_Loaded"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

View File

@@ -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 Util.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);
Canvas.SetTop(connector, vm.DataItem.ItemHeight * vm.YRatio);
}
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);
Canvas.SetTop(connector, vm.DataItem.ItemHeight * vm.YRatio);
}
}
}
}
}

View File

@@ -0,0 +1,978 @@
<UserControl x:Class="Util.DiagramDesigner.DiagramControl"
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:Util.DiagramDesigner"
xmlns:c="clr-namespace:Util.DiagramDesigner.Controls"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d" HorizontalAlignment="Center" VerticalAlignment="Center"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Util.DiagramDesigner;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<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"/>
<!-- ResizeDecorator Default Template -->
<!--
<ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="{x:Type Control}">
<Grid SnapsToDevicePixels="true">
<c:ResizeThumb Height="1" Cursor="SizeNS" Margin="0 0 0 0"
VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<c:ResizeThumb Width="1" Cursor="SizeWE" Margin="0 0 0 0"
VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
<c:ResizeThumb Width="1" Cursor="SizeWE" Margin="0 0 0 0"
VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
<c:ResizeThumb Height="1" Cursor="SizeNS" Margin="0 0 0 0"
VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
<c:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="-3 -3 0 0"
VerticalAlignment="Top" HorizontalAlignment="Left"/>
<c:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="0 -3 -3 0"
VerticalAlignment="Top" HorizontalAlignment="Right"/>
<c:ResizeThumb Width="7" Height="7" Cursor="SizeNESW" Margin="-3 0 0 -3"
VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<c:ResizeThumb Width="7" Height="7" Cursor="SizeNWSE" Margin="0 0 -3 -3"
VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
</ControlTemplate>-->
<Style TargetType="{x:Type Shape}" x:Key="ThumbCorner">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Stroke" Value="#FFC8C8C8" />
<Setter Property="StrokeThickness" Value=".5" />
<Setter Property="Width" Value="7" />
<Setter Property="Height" Value="7" />
<Setter Property="Margin" Value="-2" />
<Setter Property="Fill">
<Setter.Value>
<RadialGradientBrush Center="0.2, 0.2" GradientOrigin="0.2, 0.2" RadiusX="0.8" RadiusY="0.8">
<GradientStop Color="White" Offset="0.0" />
<GradientStop Color="Gray" Offset="0.8" />
</RadialGradientBrush>
</Setter.Value>
</Setter>
</Style>
<!--ResizeDecorator Default Template-->
<ControlTemplate x:Key="ResizeDecoratorTemplate" TargetType="{x:Type Control}">
<Grid>
<Grid Opacity="0" Margin="-3">
<c:RotateThumb x:Name="rotate" Width="7"
Height="7"
Margin="0,-20,0,0"
Cursor="Hand"
VerticalAlignment="Top"
HorizontalAlignment="Center"/>
<c:ResizeThumb Height="3"
Cursor="SizeNS"
VerticalAlignment="Top"
HorizontalAlignment="Stretch"/>
<c:ResizeThumb Width="3"
Cursor="SizeWE"
VerticalAlignment="Stretch"
HorizontalAlignment="Left"/>
<c:ResizeThumb Width="3"
Cursor="SizeWE"
VerticalAlignment="Stretch"
HorizontalAlignment="Right"/>
<c:ResizeThumb Height="3"
Cursor="SizeNS"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"/>
<c:ResizeThumb Width="7"
Height="7"
Margin="-2"
Cursor="SizeNWSE"
VerticalAlignment="Top"
HorizontalAlignment="Left"/>
<c:ResizeThumb Width="7"
Height="7"
Margin="-2"
Cursor="SizeNESW"
VerticalAlignment="Top"
HorizontalAlignment="Right"/>
<c:ResizeThumb Width="7"
Height="7"
Margin="-2"
Cursor="SizeNESW"
VerticalAlignment="Bottom"
HorizontalAlignment="Left"/>
<c:ResizeThumb Width="7"
Height="7"
Margin="-2"
Cursor="SizeNWSE"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"/>
</Grid>
<Grid IsHitTestVisible="False" Opacity="1" Margin="-3">
<Rectangle SnapsToDevicePixels="True"
StrokeThickness="1"
Margin="1"
Stroke="Gray"/>
<Line x:Name="line" StrokeThickness="1" X1="0" Y1="0" X2="0" Y2="20"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="0,-19,0,0"
Stroke="Gray"/>
<Ellipse x:Name="top" Style="{StaticResource ThumbCorner}" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="-1,-20,0,0"/>
<Ellipse Style="{StaticResource ThumbCorner}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Ellipse Style="{StaticResource ThumbCorner}" HorizontalAlignment="Right" VerticalAlignment="Top"/>
<Ellipse Style="{StaticResource ThumbCorner}" HorizontalAlignment="Left" VerticalAlignment="Bottom"/>
<Ellipse Style="{StaticResource ThumbCorner}" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ShowRotate}" Value="false">
<Setter TargetName="rotate" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="line" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="top" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ObjectDataProvider x:Key="ConnectorOrientationMenu" MethodName="GetValues" ObjectType="{x:Type sys:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="s:ConnectorOrientation" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<Style x:Key="CinchMenuItemStyle" TargetType="{x:Type MenuItem}" >
<Setter Property="Header" Value="{Binding Text}" />
<Setter Property="ItemsSource" Value="{Binding Children}" />
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
</Style>
<!-- Connector Style -->
<Style x:Key="normalConnector" TargetType="{x:Type s:Connector}">
<Setter Property="Cursor" Value="Cross" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type s:Connector}">
<Grid Width="{Binding ConnectorWidth}" Height="{Binding ConnectorHeight}">
<Grid.ContextMenu>
<ContextMenu ItemsSource="{Binding MenuOptions}" >
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<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}" />
<Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
<Setter Property="MenuItem.IsCheckable" Value="{Binding IsCheckable}" />
<Setter Property="MenuItem.IsChecked" Value="{Binding IsChecked}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Grid.ContextMenu>
<!-- transparent extra space makes connector easier to hit -->
<Rectangle Fill="Transparent" Margin="-2" />
<Rectangle Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" StrokeThickness="1" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Connector Style -->
<Style x:Key="logicalConnector" TargetType="{x:Type s:Connector}">
<Setter Property="Cursor" Value="Cross" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type s:Connector}">
<Grid>
<Grid Width="{Binding ConnectorWidth}" Height="{Binding ConnectorHeight}" HorizontalAlignment="Left" VerticalAlignment="Top">
<Grid.ContextMenu>
<ContextMenu ItemsSource="{Binding MenuOptions}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<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}" />
<Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
<Setter Property="MenuItem.IsCheckable" Value="{Binding IsCheckable}" />
<Setter Property="MenuItem.IsChecked" Value="{Binding IsChecked}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Grid.ContextMenu>
<!-- transparent extra space makes connector easier to hit -->
<Rectangle Fill="Transparent" Margin="-2" />
<Rectangle Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" StrokeThickness="1" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
</Grid>
<TextBlock x:Name="txtleft" FontSize="10" RenderTransformOrigin="0.5,0.5">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource ConectorValueConverter}">
<Binding Path="ConnectorValue" />
<Binding Path="ValueTypePoint"/>
</MultiBinding>
</TextBlock.Text>
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform Y="10" X="{Binding ElementName=txtleft,Path=Text,Converter={StaticResource ConectorOrientationConverter}}"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="txtRight" FontSize="10" RenderTransformOrigin="0.5,0.5" Visibility="Collapsed">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource ConectorValueConverter}">
<Binding Path="ConnectorValue" />
<Binding Path="ValueTypePoint"/>
</MultiBinding>
</TextBlock.Text>
<TextBlock.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform Y="10" X="5"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Value="Right" Binding="{Binding Orientation}">
<Setter TargetName="txtleft" Property="Visibility" Value="Collapsed" />
<Setter TargetName="txtRight" Property="Visibility" Value="Visible" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Connector Style -->
<Style x:Key="pointConnector" TargetType="{x:Type s:PointConnector}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type s:PointConnector}">
<Grid Width="{Binding ConnectorWidth}" Height="{Binding ConnectorHeight}">
<!-- transparent extra space makes connector easier to hit -->
<Ellipse Fill="Transparent" Margin="-2" />
<Ellipse Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" StrokeThickness="1" Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="normalConnectorContainer" TargetType="{x:Type s:ConnectorContainer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Grid>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<Rectangle Fill="#7F243859" Opacity="0.5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Visibility="{Binding ShouldInsertAnchor, Converter={StaticResource BooleanToVisibilityConverter}}">
<i:Interaction.Behaviors>
<s:ControlMouseLeftButtonDownCommandBehavior Command="{Binding AddItemCommand}" />
</i:Interaction.Behaviors>
</Rectangle>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="logicConnectorContainer" TargetType="{x:Type s:ConnectorContainer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<Grid>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.LayoutTransform>
<ScaleTransform x:Name="scale" ScaleX="{Binding ZoomValue}" ScaleY="{Binding ZoomValue}" Changed="ScaleTransform_Changed" />
</UserControl.LayoutTransform>
<Border BorderBrush="LightGray"
BorderThickness="0">
<Grid>
<ItemsControl ItemsSource="{Binding Items}"
ItemContainerStyleSelector="{x:Static s:DesignerItemsControlItemStyleSelector.Instance}">
<ItemsControl.Resources>
<Style x:Key="designerItemStyle"
TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Top"
Value="{Binding Top}" />
<Setter Property="Canvas.Left"
Value="{Binding Left}" />
<Setter Property="Canvas.ZIndex"
Value="{Binding ZIndex}" />
<Setter Property="s:SelectionProps.EnabledForSelection"
Value="True" />
<Setter Property="s:ItemConnectProps.EnabledForConnection"
Value="True" />
<Setter Property="Width"
Value="{Binding ItemWidth}" />
<Setter Property="Height"
Value="{Binding ItemHeight}" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid x:Name="selectedGrid" IsHitTestVisible="{Binding IsHitTestVisible}" >
<Grid.ContextMenu>
<ContextMenu ItemsSource="{Binding MenuOptions}" Visibility="{Binding ShowMenuOptions,Converter={StaticResource BooleanToVisibilityConverter}}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<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}" />
<Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
<Setter Property="MenuItem.IsCheckable" Value="{Binding IsCheckable}" />
<Setter Property="MenuItem.IsChecked" Value="{Binding IsChecked}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Grid.ContextMenu>
<!-- PART_DragThumb -->
<c:DragThumb x:Name="PART_DragThumb"
Cursor="SizeAll" >
<c:DragThumb.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding EditCommand}" CommandParameter="{Binding }" />
</c:DragThumb.InputBindings>
</c:DragThumb>
<Grid RenderTransformOrigin="0.5,0.5">
<!-- PART_ResizeDecorator -->
<Control x:Name="PART_ResizeDecorator"
Visibility="Collapsed"
Template="{StaticResource ResizeDecoratorTemplate}"/>
<!-- PART_ContentPresenter -->
<ContentPresenter x:Name="PART_ContentPresenter"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Content="{TemplateBinding Content}" />
<Control x:Name="PART_Text" Margin="5">
<Control.Style>
<Style TargetType="Control">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ShowText}" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<s:TextControl x:Name="PART_Text" />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Control.Style>
</Control>
<!-- PART_ConnectorDecorator -->
<Grid Margin="-5"
x:Name="PART_ConnectorDecorator">
<s:Connector DataContext="{Binding LeftConnector}" Style="{StaticResource normalConnector}"
Orientation="Left"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Visibility="{Binding Path=ShowConnectors, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
<s:Connector DataContext="{Binding TopConnector}" Style="{StaticResource normalConnector}"
Orientation="Top"
VerticalAlignment="Top"
HorizontalAlignment="Center"
Visibility="{Binding Path=ShowConnectors, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
<s:Connector DataContext="{Binding RightConnector}" Style="{StaticResource normalConnector}"
Orientation="Right"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Visibility="{Binding Path=ShowConnectors, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
<s:Connector DataContext="{Binding BottomConnector}" Style="{StaticResource normalConnector}"
Orientation="Bottom"
VerticalAlignment="Bottom"
HorizontalAlignment="Center"
Visibility="{Binding Path=ShowConnectors, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
</Grid>
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform Angle="{Binding Angle}" />
<ScaleTransform x:Name="scale" ScaleX="{Binding ScaleX}" ScaleY="{Binding ScaleY}"></ScaleTransform>
</TransformGroup>
</Grid.RenderTransform>
</Grid>
</Grid>
<DataTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="True" Binding="{Binding IsSelected}"/>
<Condition Value="{x:Static sys:Guid.Empty}" Binding="{Binding ParentId}"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="PART_ResizeDecorator" Property="Visibility" Value="Visible"/>
</MultiDataTrigger>
<Trigger Property="IsMouseOver"
Value="true">
<Setter TargetName="PART_ConnectorDecorator" Property="Visibility" Value="Visible"/>
</Trigger>
<DataTrigger Value="True"
Binding="{Binding RelativeSource={RelativeSource Self},Path=IsDragConnectionOver}">
<Setter TargetName="PART_ConnectorDecorator" Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Value="0"
Binding="{Binding Connectors.Count}">
<Setter TargetName="PART_ConnectorDecorator" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="10" Color="{Binding ColorViewModel.ShadowColor}"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ColorViewModel.ShadowColor}" Value="Transparent">
<Setter Property="Effect" Value="{x:Null}"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="connectorItemStyle"
TargetType="{x:Type ContentPresenter}">
<Setter Property="Width"
Value="{Binding Area.Width}" />
<Setter Property="Height"
Value="{Binding Area.Height}" />
<Setter Property="Canvas.Top"
Value="{Binding Area.Top}" />
<Setter Property="Canvas.Left"
Value="{Binding Area.Left}" />
<Setter Property="Canvas.ZIndex"
Value="{Binding ZIndex}" />
<Setter Property="s:SelectionProps.EnabledForSelection"
Value="True" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="删除" Command="{Binding DeleteConnectionCommand}" CommandParameter="{Binding}"/>
</ContextMenu>
</Grid.ContextMenu>
<Canvas Margin="0"
x:Name="selectedGrid"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<Canvas.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding EditCommand}" CommandParameter="{Binding }" />
</Canvas.InputBindings>
<Polyline x:Name="poly"
Points="{Binding Path=ConnectionPoints, Converter={x:Static s:ConnectionPathConverter.Instance}}"
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
StrokeThickness="{Binding ColorViewModel.LineWidth}"
StrokeDashArray="{Binding ColorViewModel.LineDashStyle,Converter={StaticResource LineDashConverter}}" />
<Path x:Name="rightarrow"
Data="{Binding ColorViewModel.RightArrowPathStyle,Converter={StaticResource ArrowPathConverter}}"
Visibility="{Binding Path=IsFullConnection, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
Fill="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
HorizontalAlignment="Left"
Height="{Binding ColorViewModel.RightArrowSizeStyle, Converter={StaticResource ArrowSizeConverter}}"
Width="{Binding ColorViewModel.RightArrowSizeStyle, Converter={StaticResource ArrowSizeConverter}}"
Canvas.Left="{Binding EndPoint.X}"
Canvas.Top="{Binding EndPoint.Y}"
Stretch="Fill"
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
VerticalAlignment="Top"
RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<RotateTransform x:Name="rightrot" />
</Path.RenderTransform>
</Path>
<Path x:Name="leftarrow"
Data="{Binding ColorViewModel.LeftArrowPathStyle,Converter={StaticResource ArrowPathConverter}}"
Visibility="{Binding Path=IsFullConnection, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
Fill="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
HorizontalAlignment="Left"
Height="{Binding ColorViewModel.LeftArrowSizeStyle, Converter={StaticResource ArrowSizeConverter}}"
Width="{Binding ColorViewModel.LeftArrowSizeStyle, Converter={StaticResource ArrowSizeConverter}}"
Canvas.Left="{Binding StartPoint.X}"
Canvas.Top="{Binding StartPoint.Y}"
Stretch="Fill"
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
VerticalAlignment="Top"
RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<RotateTransform x:Name="leftrot" />
</Path.RenderTransform>
</Path>
</Canvas>
<!-- PART_DragThumb -->
<c:DragThumb x:Name="PART_DragThumb"
Cursor="SizeAll" >
<c:DragThumb.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding EditCommand}" CommandParameter="{Binding }" />
</c:DragThumb.InputBindings>
</c:DragThumb>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Value="True"
Binding="{Binding IsSelected}">
<Setter TargetName="poly"
Property="Stroke"
Value="Black" />
<Setter TargetName="rightarrow"
Property="Stroke"
Value="Black" />
<Setter TargetName="rightarrow"
Property="Fill"
Value="Black" />
</DataTrigger>
<!--右箭头-->
<DataTrigger Binding="{Binding Path=SinkConnectorInfo.Orientation}"
Value="Left">
<Setter TargetName="rightarrow"
Property="Margin"
Value="-10,-5,0,0" />
<Setter TargetName="rightarrow"
Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="90" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=SinkConnectorInfo.Orientation}"
Value="Top">
<Setter TargetName="rightarrow"
Property="Margin"
Value="-5,-10,0,0" />
<Setter TargetName="rightarrow"
Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=SinkConnectorInfo.Orientation}"
Value="Right">
<Setter TargetName="rightarrow"
Property="Margin"
Value="0,-5,0,0" />
<Setter TargetName="rightarrow"
Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="-90" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=SinkConnectorInfo.Orientation}"
Value="Bottom">
<Setter TargetName="rightarrow"
Property="Margin"
Value="-5,0,0,0" />
<Setter TargetName="rightarrow"
Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="0" />
</Setter.Value>
</Setter>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="True" Binding="{Binding SinkConnectorInfo.IsInnerPoint}"/>
<Condition Value="0" Binding="{Binding SinkConnectorInfo.XRatio}"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="rightarrow" Property="Visibility" Value="Hidden"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="True" Binding="{Binding SinkConnectorInfo.IsInnerPoint}"/>
<Condition Value="1" Binding="{Binding SinkConnectorInfo.XRatio}"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="rightarrow" Property="Visibility" Value="Hidden"/>
</MultiDataTrigger>
<DataTrigger Binding="{Binding Path=ColorViewModel.RightArrowStyle}" Value="None">
<Setter TargetName="rightarrow" Property="Visibility" Value="Hidden"/>
</DataTrigger>
<!--左箭头-->
<DataTrigger Binding="{Binding Path=SourceConnectorInfo.Orientation}"
Value="Left">
<Setter TargetName="leftarrow"
Property="Margin"
Value="-10,-5,0,0" />
<Setter TargetName="leftarrow"
Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="90" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=SourceConnectorInfo.Orientation}"
Value="Top">
<Setter TargetName="leftarrow"
Property="Margin"
Value="-5,-10,0,0" />
<Setter TargetName="leftarrow"
Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="180" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=SourceConnectorInfo.Orientation}"
Value="Right">
<Setter TargetName="leftarrow"
Property="Margin"
Value="0,-5,0,0" />
<Setter TargetName="leftarrow"
Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="-90" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=SourceConnectorInfo.Orientation}"
Value="Bottom">
<Setter TargetName="leftarrow"
Property="Margin"
Value="-5,0,0,0" />
<Setter TargetName="leftarrow"
Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="0" />
</Setter.Value>
</Setter>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="True" Binding="{Binding SourceConnectorInfo.IsInnerPoint}"/>
<Condition Value="0" Binding="{Binding SourceConnectorInfo.XRatio}"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="leftarrow" Property="Visibility" Value="Hidden"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="True" Binding="{Binding SourceConnectorInfo.IsInnerPoint}"/>
<Condition Value="1" Binding="{Binding SourceConnectorInfo.XRatio}"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="leftarrow" Property="Visibility" Value="Hidden"/>
</MultiDataTrigger>
<DataTrigger Binding="{Binding Path=ColorViewModel.LeftArrowStyle}" Value="None">
<Setter TargetName="leftarrow" Property="Visibility" Value="Hidden"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="gifimageItemStyle"
TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Top"
Value="{Binding Top}" />
<Setter Property="Canvas.Left"
Value="{Binding Left}" />
<Setter Property="Canvas.ZIndex"
Value="{Binding ZIndex}" />
<Setter Property="s:SelectionProps.EnabledForSelection"
Value="True" />
<Setter Property="s:ItemConnectProps.EnabledForConnection"
Value="True" />
<Setter Property="Width"
Value="{Binding ItemWidth}" />
<Setter Property="Height"
Value="{Binding ItemHeight}" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid x:Name="selectedGrid" IsHitTestVisible="{Binding IsHitTestVisible}">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="插入点" IsCheckable="True" IsChecked="{Binding ShouldInsertAnchor}" />
<MenuItem Header="选择" ItemsSource="{Binding MenuOptions}" ItemContainerStyle="{StaticResource CinchMenuItemStyle}"/>
</ContextMenu>
</Grid.ContextMenu>
<!-- PART_DragThumb -->
<c:DragThumb x:Name="PART_DragThumb"
Cursor="SizeAll" />
<Grid RenderTransformOrigin="0.5,0.5">
<!-- PART_ResizeDecorator -->
<Control x:Name="PART_ResizeDecorator"
Visibility="Collapsed"
Template="{StaticResource ResizeDecoratorTemplate}"/>
<!-- PART_ContentPresenter -->
<ContentPresenter x:Name="PART_ContentPresenter"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Content="{TemplateBinding Content}" />
<!-- PART_ConnectorDecorator -->
<s:ConnectorContainer x:Name="PART_ConnectorContainer" Visibility="Hidden" Style="{StaticResource normalConnectorContainer}" ItemsSource="{Binding Connectors}">
<s:ConnectorContainer.ItemTemplate>
<DataTemplate>
<s:Connector Style="{StaticResource normalConnector}"/>
</DataTemplate>
</s:ConnectorContainer.ItemTemplate>
</s:ConnectorContainer>
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform Angle="{Binding Angle}" />
<ScaleTransform x:Name="scale" ScaleX="{Binding ScaleX}" ScaleY="{Binding ScaleY}"></ScaleTransform>
</TransformGroup>
</Grid.RenderTransform>
</Grid>
</Grid>
<DataTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="True" Binding="{Binding IsSelected}"/>
<Condition Value="{x:Static sys:Guid.Empty}" Binding="{Binding ParentId}"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="PART_ResizeDecorator" Property="Visibility" Value="Visible"/>
</MultiDataTrigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="PART_ConnectorContainer" Property="Visibility" Value="Visible" />
</Trigger>
<DataTrigger Value="True" Binding="{Binding IsDragConnectionOver}">
<Setter TargetName="PART_ConnectorContainer" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="logicalItemStyle"
TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Top"
Value="{Binding Top}" />
<Setter Property="Canvas.Left"
Value="{Binding Left}" />
<Setter Property="Canvas.ZIndex"
Value="{Binding ZIndex}" />
<Setter Property="s:SelectionProps.EnabledForSelection"
Value="True" />
<Setter Property="s:ItemConnectProps.EnabledForConnection"
Value="True" />
<Setter Property="Width"
Value="{Binding ItemWidth}" />
<Setter Property="Height"
Value="{Binding ItemHeight}" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid x:Name="selectedGrid">
<Grid.ContextMenu>
<ContextMenu ItemsSource="{Binding MenuOptions}" Visibility="{Binding ShowMenuOptions,Converter={StaticResource BooleanToVisibilityConverter}}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<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}" />
<Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
<Setter Property="MenuItem.IsCheckable" Value="{Binding IsCheckable}" />
<Setter Property="MenuItem.IsChecked" Value="{Binding IsChecked}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Grid.ContextMenu>
<!--PART_ConnectorDecorator-->
<s:ConnectorContainer x:Name="PART_ConnectorContainer" Style="{StaticResource logicConnectorContainer}" ItemsSource="{Binding Connectors}" Margin="-4,0,0,0">
<s:ConnectorContainer.ItemTemplate>
<DataTemplate>
<Grid>
<s:Connector Style="{StaticResource logicalConnector}"/>
</Grid>
</DataTemplate>
</s:ConnectorContainer.ItemTemplate>
</s:ConnectorContainer>
<!-- PART_DragThumb -->
<c:DragThumb x:Name="PART_DragThumb"
Cursor="SizeAll" >
<c:DragThumb.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding EditCommand}" CommandParameter="{Binding }" />
</c:DragThumb.InputBindings>
</c:DragThumb>
<!-- PART_ResizeDecorator -->
<Control x:Name="PART_ResizeDecorator"
Visibility="Collapsed"
Template="{StaticResource ResizeDecoratorTemplate}"/>
<!-- PART_ContentPresenter -->
<ContentPresenter x:Name="PART_ContentPresenter"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Content="{TemplateBinding Content}" />
</Grid>
<DataTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Value="True" Binding="{Binding IsSelected}"/>
<Condition Value="{x:Static sys:Guid.Empty}" Binding="{Binding ParentId}"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="PART_ResizeDecorator" Property="Visibility" Value="Visible"/>
</MultiDataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="pointItemStyle"
TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Top"
Value="{Binding Top}" />
<Setter Property="Canvas.Left"
Value="{Binding Left}" />
<Setter Property="Canvas.ZIndex"
Value="{Binding ZIndex}" />
<Setter Property="s:SelectionProps.EnabledForSelection"
Value="True" />
<Setter Property="Width"
Value="{Binding ItemWidth}" />
<Setter Property="Height"
Value="{Binding ItemHeight}" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid x:Name="selectedGrid" Visibility="{Binding Path=ShowConnectors, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<!-- PART_ConnectorDecorator -->
<Grid Margin="-5"
x:Name="PART_ConnectorDecorator">
<s:PointConnector DataContext="{Binding TopConnector}" Style="{StaticResource pointConnector}"/>
</Grid>
<!-- PART_DragThumb -->
<c:DragThumb x:Name="PART_DragThumb"
Cursor="SizeAll" />
</Grid>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter TargetName="PART_ConnectorDecorator" Property="Visibility" Value="Visible"/>
</Trigger>
<DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self},Path=IsDragConnectionOver}">
<Setter TargetName="PART_ConnectorDecorator" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="linkpointItemStyle"
TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Top"
Value="{Binding Top}" />
<Setter Property="Canvas.Left"
Value="{Binding Left}" />
<Setter Property="Canvas.ZIndex"
Value="{Binding ZIndex}" />
<Setter Property="s:SelectionProps.EnabledForSelection"
Value="True" />
<Setter Property="s:ItemConnectProps.EnabledForConnection"
Value="True" />
<Setter Property="Width"
Value="{Binding ItemWidth}" />
<Setter Property="Height"
Value="{Binding ItemHeight}" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid x:Name="selectedGrid">
<!-- PART_ConnectorDecorator -->
<Grid Margin="-5"
x:Name="PART_ConnectorDecorator">
<s:Connector DataContext="{Binding TopConnector}" Style="{StaticResource normalConnector}"
Orientation="Right"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Visibility="{Binding Path=ShowConnectors, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
</Grid>
<!-- PART_DragThumb -->
<c:DragThumb x:Name="PART_DragThumb"
Cursor="SizeAll" />
</Grid>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter TargetName="PART_ConnectorDecorator" Property="Visibility" Value="Visible"/>
</Trigger>
<DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self},Path=IsDragConnectionOver}">
<Setter TargetName="PART_ConnectorDecorator" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<s:DesignerCanvas Loaded="DesignerCanvas_Loaded"
Height="{Binding PageSize.Height}"
Width="{Binding PageSize.Width}"
ShowGrid="{Binding ShowGrid}"
GridCellSize="{Binding GridCellSize}"
GridMargin="{Binding GridMargin}"
GridColor="{Binding GridColor}"
Background="{Binding PageBackground,Converter={StaticResource ColorBrushConverter}}"
AllowDrop="True">
</s:DesignerCanvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Border>
</UserControl>

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 Util.DiagramDesigner
{
/// <summary>
/// Interaction logic for DiagramControl.xaml
/// </summary>
public partial class DiagramControl : UserControl
{
public DiagramControl()
{
InitializeComponent();
}
public static readonly DependencyProperty ZoomValueProperty = DependencyProperty.Register("ZoomValue", typeof(double), typeof(DiagramControl), new UIPropertyMetadata(1d));
public double ZoomValue
{
get
{
return (double)GetValue(ZoomValueProperty);
}
set
{
SetValue(ZoomValueProperty, value);
}
}
private void DesignerCanvas_Loaded(object sender, RoutedEventArgs e)
{
}
private async void ScaleTransform_Changed(object sender, EventArgs e)
{
await System.Threading.Tasks.Task.Delay(100);
ZoomValue = scale.ScaleX;
}
}
}

View File

@@ -0,0 +1,101 @@
<UserControl x:Class="Util.DiagramDesigner.TextControl"
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:Util.DiagramDesigner"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<s:ColorBrushConverter x:Key="ColorBrushConverter" />
<s:TrueToFalseConverter x:Key="TrueToFalseConverter"/>
<!--TextBox默认样式-->
<Style TargetType="{x:Type TextBox}" x:Key="WaterTextBox">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="Width" Value="Auto"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid x:Name="PART_Root">
<Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" />
<Grid x:Name="PART_InnerGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!--内容区域-->
<ScrollViewer x:Name="PART_ContentHost" BorderThickness="0" Grid.Column="1" IsTabStop="False" Margin="2"
VerticalAlignment="Stretch" Background="{x:Null}" >
<ScrollViewer.Effect>
<DropShadowEffect x:Name="effect" Color="{Binding FontViewModel.TextEffectColor}" ></DropShadowEffect>
</ScrollViewer.Effect>
</ScrollViewer>
<!--水印-->
<TextBlock x:Name="Message" Padding="{TemplateBinding Padding}" Visibility="Collapsed"
Text="{TemplateBinding s:ControlAttachProperty.Watermark}" Grid.Column="1"
Foreground="{TemplateBinding Foreground}" IsHitTestVisible="False" Opacity="0.5"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="5,2,5,2" />
</Grid>
</Grid>
<ControlTemplate.Triggers>
<!--显示水印-->
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
<Setter TargetName="Message" Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding FontViewModel.TextEffectColor}" Value="Transparent">
<Setter TargetName="PART_ContentHost" Property="Effect" Value="{x:Null}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid IsHitTestVisible="{Binding IsHitTestVisible}">
<TextBox x:Name="PART_TextBlock"
Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding FontViewModel.FontColor,Converter={StaticResource ColorBrushConverter}}"
FontSize="{Binding FontViewModel.FontSize}"
FontFamily="{Binding FontViewModel.FontFamily}"
FontWeight="{Binding FontViewModel.FontWeight}"
FontStyle="{Binding FontViewModel.FontStyle}"
FontStretch="{Binding FontViewModel.FontStretch}"
TextDecorations="{Binding FontViewModel.TextDecorations}"
HorizontalContentAlignment="{Binding FontViewModel.HorizontalAlignment}"
VerticalContentAlignment="{Binding FontViewModel.VerticalAlignment}"
TextBlock.LineHeight="{Binding FontViewModel.LineHeight}"
AcceptsReturn="True"
s:ControlAttachProperty.Watermark="{Binding Path=(s:ControlAttachProperty.Watermark),RelativeSource={RelativeSource AncestorType={x:Type s:TextControl}}}"
Style="{StaticResource WaterTextBox}" IsReadOnly="True">
</TextBox>
<TextBox x:Name="PART_ShowText"
Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding FontViewModel.FontColor,Converter={StaticResource ColorBrushConverter}}"
IsReadOnly="{Binding IsReadOnly}"
FontSize="{Binding FontViewModel.FontSize}"
FontFamily="{Binding FontViewModel.FontFamily}"
FontWeight="{Binding FontViewModel.FontWeight}"
FontStyle="{Binding FontViewModel.FontStyle}"
FontStretch="{Binding FontViewModel.FontStretch}"
TextDecorations="{Binding FontViewModel.TextDecorations}"
HorizontalContentAlignment="{Binding FontViewModel.HorizontalAlignment}"
VerticalContentAlignment="{Binding FontViewModel.VerticalAlignment}"
TextBlock.LineHeight="{Binding FontViewModel.LineHeight}"
AcceptsReturn="True"
s:ControlAttachProperty.Watermark="{Binding Path=(s:ControlAttachProperty.Watermark),RelativeSource={RelativeSource AncestorType={x:Type s:TextControl}}}"
Style="{StaticResource WaterTextBox}" Visibility="Collapsed">
</TextBox>
</Grid>
</UserControl>

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Text;
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 Util.DiagramDesigner
{
/// <summary>
/// TextControl.xaml 的交互逻辑
/// </summary>
public partial class TextControl : UserControl
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"DoubleEdit", typeof(bool), typeof(TextControl), new FrameworkPropertyMetadata(
true));
public bool DoubleEdit
{
get => (bool)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public TextControl()
{
InitializeComponent();
this.Loaded += TextControl_Loaded;
}
private void TextControl_Loaded(object sender, RoutedEventArgs e)
{
this.Loaded -= TextControl_Loaded;
PART_ShowText.Visibility = Visibility.Visible;
PART_TextBlock.Visibility = Visibility.Collapsed;
PART_ShowText.Focus();
if (!string.IsNullOrEmpty(PART_ShowText.Text))
{
PART_ShowText.SelectionStart = PART_ShowText.Text.Length;
}
(this.DataContext as SelectableDesignerItemViewModelBase).PropertyChanged += TextControl_PropertyChanged;
TextControl_PropertyChanged(this.DataContext, new System.ComponentModel.PropertyChangedEventArgs("IsSelected"));
}
private void TextControl_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsSelected")
{
if (sender is SelectableDesignerItemViewModelBase itemViewModelBase)
{
if (itemViewModelBase.IsSelected == false)
{
PART_ShowText.Visibility = Visibility.Collapsed;
PART_TextBlock.Visibility = Visibility.Visible;
}
}
}
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
base.OnPreviewMouseDown(e);
if (DoubleEdit == false)
{
PART_ShowText.Visibility = Visibility.Visible;
PART_TextBlock.Visibility = Visibility.Collapsed;
PART_ShowText.Focus();
if (!string.IsNullOrEmpty(PART_ShowText.Text))
{
PART_ShowText.SelectionStart = PART_ShowText.Text.Length;
}
}
}
protected override void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
{
base.OnPreviewMouseDoubleClick(e);
if (DoubleEdit == true)
{
PART_ShowText.Visibility = Visibility.Visible;
PART_TextBlock.Visibility = Visibility.Collapsed;
PART_ShowText.Focus();
if (!string.IsNullOrEmpty(PART_ShowText.Text))
{
PART_ShowText.SelectionStart = PART_ShowText.Text.Length;
}
}
}
}
public class ControlAttachProperty
{
#region WatermarkProperty
/// <summary>
/// 水印
/// </summary>
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached(
"Watermark", typeof(string), typeof(ControlAttachProperty), new FrameworkPropertyMetadata(""));
public static string GetWatermark(DependencyObject d)
{
return (string)d.GetValue(WatermarkProperty);
}
public static void SetWatermark(DependencyObject obj, string value)
{
obj.SetValue(WatermarkProperty, value);
}
#endregion
}
}

View File

@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net462;net472</TargetFrameworks>
<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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WpfAnimatedGif\WpfAnimatedGif.csproj" />
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains(NETCOREAPP)) == true">
<PackageReference Include="System.Drawing.Common" Version="5.0.1" />
</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>

View File

@@ -0,0 +1,114 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net462;net472</TargetFrameworks>
<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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WpfAnimatedGif\WpfAnimatedGif.csproj" />
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains(NETCOREAPP)) == true">
<PackageReference Include="System.Drawing.Common" Version="5.0.1" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<None Update="Images\Gifs\Null.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\刮板.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\压缩机.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\双馈风机.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\圆锥破碎机.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\振动筛.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\水泵.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\泥浆泵侧面.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\泥浆泵前端.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\泵.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\皮带.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\破碎机.PNG">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\离心机.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\设备#1.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\转子实验台.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\风力发电机.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\风机.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Images\Gifs\风机轴.jpg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\microsoft.xaml.behaviors.wpf\1.1.31\lib\net45\Microsoft.Xaml.Behaviors.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\mscorlib.dll" />
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\newtonsoft.json\13.0.1\lib\net45\Newtonsoft.Json.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\PresentationCore.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\PresentationFramework.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Core.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Data.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Drawing.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.IO.Compression.FileSystem.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Numerics.dll" />
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\system.reactive\5.0.0\lib\net472\System.Reactive.dll" />
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\system.runtime.compilerservices.unsafe\4.5.3\ref\net461\System.Runtime.CompilerServices.Unsafe.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Runtime.Serialization.dll" />
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\system.threading.tasks.extensions\4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Windows.Controls.Ribbon.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Windows.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Windows.Forms.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Xaml.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Xml.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Xml.Linq.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\UIAutomationClient.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\UIAutomationClientsideProviders.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\UIAutomationProvider.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\UIAutomationTypes.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\WindowsBase.dll" />
<ReferencePath Include="F:\AIStudio.Wpf.Diagram\WpfAnimatedGif\bin\Debug\net4\WpfAnimatedGif.dll" />
</ItemGroup>
<ItemGroup>
<Compile Include="F:\AIStudio.Wpf.Diagram\Util.DiagramDesigner\obj\Debug\net472\UserControls\ConnectorContainer.g.cs" />
<Compile Include="F:\AIStudio.Wpf.Diagram\Util.DiagramDesigner\obj\Debug\net472\UserControls\DiagramControl.g.cs" />
<Compile Include="F:\AIStudio.Wpf.Diagram\Util.DiagramDesigner\obj\Debug\net472\UserControls\TextControl.g.cs" />
<Compile Include="F:\AIStudio.Wpf.Diagram\Util.DiagramDesigner\obj\Debug\net472\GeneratedInternalTypeHelper.g.cs" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,168 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net462;net472</TargetFrameworks>
<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" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WpfAnimatedGif\WpfAnimatedGif.csproj" />
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains(NETCOREAPP)) == true">
<PackageReference Include="System.Drawing.Common" Version="5.0.1" />
</ItemGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<None Update="Images\Gifs\car_chase.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\Microsoft.Win32.Primitives.dll" />
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\microsoft.xaml.behaviors.wpf\1.1.31\lib\net45\Microsoft.Xaml.Behaviors.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\mscorlib.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\netfx.force.conflicts.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\netstandard.dll" />
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\newtonsoft.json\13.0.1\lib\net45\Newtonsoft.Json.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\PresentationCore.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\PresentationFramework.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.AppContext.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Collections.Concurrent.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Collections.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Collections.NonGeneric.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Collections.Specialized.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.ComponentModel.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.ComponentModel.EventBasedAsync.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.ComponentModel.Primitives.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.ComponentModel.TypeConverter.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Console.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Core.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Data.Common.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Data.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Diagnostics.Contracts.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Diagnostics.Debug.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Diagnostics.FileVersionInfo.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Diagnostics.Process.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Diagnostics.StackTrace.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Diagnostics.TextWriterTraceListener.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Diagnostics.Tools.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Diagnostics.TraceSource.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Diagnostics.Tracing.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Drawing.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Drawing.Primitives.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Dynamic.Runtime.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Globalization.Calendars.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Globalization.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Globalization.Extensions.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.Compression.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.IO.Compression.FileSystem.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.Compression.ZipFile.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.FileSystem.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.FileSystem.DriveInfo.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.FileSystem.Primitives.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.FileSystem.Watcher.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.IsolatedStorage.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.MemoryMappedFiles.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.Pipes.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.IO.UnmanagedMemoryStream.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Linq.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Linq.Expressions.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Linq.Parallel.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Linq.Queryable.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.Http.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.NameResolution.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.NetworkInformation.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.Ping.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.Primitives.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.Requests.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.Security.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.Sockets.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.WebHeaderCollection.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.WebSockets.Client.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Net.WebSockets.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Numerics.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.ObjectModel.dll" />
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\system.reactive\5.0.0\lib\netstandard2.0\System.Reactive.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Reflection.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Reflection.Extensions.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Reflection.Primitives.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Resources.Reader.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Resources.ResourceManager.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Resources.Writer.dll" />
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\system.runtime.compilerservices.unsafe\4.5.3\ref\net461\System.Runtime.CompilerServices.Unsafe.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.CompilerServices.VisualC.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.Extensions.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.Handles.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.InteropServices.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net462\lib\System.Runtime.InteropServices.RuntimeInformation.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.Numerics.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Runtime.Serialization.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.Serialization.Formatters.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.Serialization.Json.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.Serialization.Primitives.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Runtime.Serialization.Xml.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Security.Claims.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Security.Cryptography.Algorithms.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Security.Cryptography.Csp.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Security.Cryptography.Encoding.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Security.Cryptography.Primitives.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Security.Cryptography.X509Certificates.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Security.Principal.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Security.SecureString.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Text.Encoding.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Text.Encoding.Extensions.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Text.RegularExpressions.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Threading.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Threading.Overlapped.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Threading.Tasks.dll" />
<ReferencePath Include="C:\Users\Administrator\.nuget\packages\system.threading.tasks.extensions\4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Threading.Tasks.Parallel.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Threading.Thread.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Threading.ThreadPool.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Threading.Timer.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.ValueTuple.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Windows.Controls.Ribbon.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Xaml.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Xml.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Xml.Linq.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Xml.ReaderWriter.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Xml.XDocument.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Xml.XmlDocument.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Xml.XmlSerializer.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Xml.XPath.dll" />
<ReferencePath Include="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib\System.Xml.XPath.XDocument.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\UIAutomationClient.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\UIAutomationClientsideProviders.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\UIAutomationProvider.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\UIAutomationTypes.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\WindowsBase.dll" />
<ReferencePath Include="F:\AIStudio.Wpf.Diagram\WpfAnimatedGif\bin\Debug\net4\WpfAnimatedGif.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.ComponentModel.Annotations.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.Reflection.Emit.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.Reflection.Emit.ILGeneration.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.Reflection.Emit.Lightweight.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.Runtime.InteropServices.WindowsRuntime.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.ServiceModel.Duplex.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.ServiceModel.Http.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.ServiceModel.NetTcp.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.ServiceModel.Primitives.dll" />
<ReferencePath Include="C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\Facades\System.ServiceModel.Security.dll" />
</ItemGroup>
<ItemGroup>
<Compile Include="F:\AIStudio.Wpf.Diagram\Util.DiagramDesigner\obj\Debug\net462\UserControls\ConnectorContainer.g.cs" />
<Compile Include="F:\AIStudio.Wpf.Diagram\Util.DiagramDesigner\obj\Debug\net462\UserControls\DiagramControl.g.cs" />
<Compile Include="F:\AIStudio.Wpf.Diagram\Util.DiagramDesigner\obj\Debug\net462\UserControls\TextControl.g.cs" />
<Compile Include="F:\AIStudio.Wpf.Diagram\Util.DiagramDesigner\obj\Debug\net462\GeneratedInternalTypeHelper.g.cs" />
</ItemGroup>
</Project>

Some files were not shown because too many files have changed in this diff Show More