整理一下项目文件

This commit is contained in:
艾竹
2022-10-28 22:45:39 +08:00
parent 334297b074
commit 513937c1d6
598 changed files with 684 additions and 544 deletions

View File

@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<None Remove="Images\file.png" />
<None Remove="Images\FormatPainter.cur" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.31" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Reactive" Version="5.0.0" />
<PackageReference Include="WpfAnimatedGif" Version="2.0.0" />
</ItemGroup>
<ItemGroup Condition="$(DefineConstants.Contains(NETCOREAPP)) == true">
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
</ItemGroup>
<ItemGroup>
<Resource Include="Images\file.png" />
<Resource Include="Images\FormatPainter.cur" />
</ItemGroup>
<ItemGroup>
<None Update="Images\Gifs\car_chase.gif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

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 AIStudio.Wpf.DiagramDesigner
{
public class RubberbandAdorner : Adorner
{
private Point? startPoint;
private Point? endPoint;
private List<Point> pointList = new List<Point>();
private List<PointDesignerItemViewModel> pointDesignerItemViewModelList = new List<PointDesignerItemViewModel>();
private Pen rubberbandPen;
private DesignerCanvas _designerCanvas;
private IDiagramViewModel _viewModel { get { return _designerCanvas.DataContext as IDiagramViewModel; } }
private IDiagramServiceProvider _service { get { return DiagramServicesProvider.Instance.Provider; } }
public RubberbandAdorner(DesignerCanvas designerCanvas, Point? dragStartPoint)
: base(designerCanvas)
{
this._designerCanvas = designerCanvas;
this.startPoint = dragStartPoint;
rubberbandPen = new Pen(Brushes.LightSlateGray, 1);
rubberbandPen.DashStyle = new DashStyle(new double[] { 2 }, 1);
}
protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (!this.IsMouseCaptured)
this.CaptureMouse();
endPoint = e.GetPosition(this);
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polyline)
{
if (pointList.Count == 0 && this.startPoint.HasValue)
{
pointList.Add(this.startPoint.Value);
}
pointList.Add(endPoint.Value);
}
UpdateSelection();
this.InvalidateVisual();
}
else if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
{
if (pointList.Count == 0 && this.startPoint.HasValue)
{
pointList.Add(this.startPoint.Value);
var item = new PointDesignerItemViewModel(startPoint.Value);
item.ShowConnectors = true;
_viewModel.DirectAddItemCommand.Execute(item);
pointDesignerItemViewModelList.Add(item);
}
}
else
{
if (this.IsMouseCaptured) this.ReleaseMouseCapture();
}
e.Handled = true;
}
protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e)
{
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine && e.ChangedButton == MouseButton.Left )
{
endPoint = e.GetPosition(this);
bool isend = false;
var connector = ControlExtession.TryFindFromPoint<PointConnector>(this._designerCanvas, endPoint.Value);
if (connector != null)
{
if (object.Equals(connector.DataContext, pointDesignerItemViewModelList[0].TopConnector))
{
isend = true;
}
}
if (isend == false)
{
pointList.Add(endPoint.Value);
var item = new PointDesignerItemViewModel(endPoint.Value);
item.ShowConnectors = true;
_viewModel.DirectAddItemCommand.Execute(item);
pointDesignerItemViewModelList.Add(item);
UpdateSelection();
this.InvalidateVisual();
return;
}
else
{
this._service.DrawModeViewModel.SetDrawMode(DrawMode.Polygon);
}
}
// release mouse capture
if (this.IsMouseCaptured) this.ReleaseMouseCapture();
// remove this adorner from adorner layer
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this._designerCanvas);
if (adornerLayer != null)
adornerLayer.Remove(this);
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Line ||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Rectangle ||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Ellipse ||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polyline ||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polygon ||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine ||
this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
{
if (this.startPoint.HasValue && this.endPoint.HasValue)
{
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polyline
|| this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Polygon
|| this._service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
{
ShapeDesignerItemViewModel itemBase = new ShapeDesignerItemViewModel(this._service.DrawModeViewModel.GetDrawMode(), pointList);
_viewModel.AddItemCommand.Execute(itemBase);
itemBase.PointDesignerItemViewModels.ForEach(p =>
{
p.ParentId = itemBase.Id;
_viewModel.DirectAddItemCommand.Execute(p);
});
}
else if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Text)
{
TextDesignerItemViewModel itemBase = new TextDesignerItemViewModel();
Point position = e.GetPosition(this);
itemBase.Left = Math.Min(this.startPoint.Value.X, this.endPoint.Value.X);
itemBase.Top = Math.Min(this.startPoint.Value.Y, this.endPoint.Value.Y);
itemBase.ItemWidth = Math.Abs(this.endPoint.Value.X - this.startPoint.Value.X);
itemBase.ItemHeight = Math.Abs(this.endPoint.Value.Y - this.startPoint.Value.Y);
_viewModel.AddItemCommand.Execute(itemBase);
}
else
{
ShapeDesignerItemViewModel itemBase = new ShapeDesignerItemViewModel(this._service.DrawModeViewModel.GetDrawMode(), new List<Point> { this.startPoint.Value, this.endPoint.Value });
_viewModel.AddItemCommand.Execute(itemBase);
itemBase.PointDesignerItemViewModels.ForEach(p =>
{
p.ParentId = itemBase.Id;
_viewModel.DirectAddItemCommand.Execute(p);
});
}
}
this._service.DrawModeViewModel.ResetDrawMode();
}
pointDesignerItemViewModelList.ForEach(p => _viewModel.DirectRemoveItemCommand.Execute(p));
e.Handled = true;
}
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
// without a background the OnMouseMove event would not be fired !
// Alternative: implement a Canvas as a child of this adorner, like
// the ConnectionAdorner does.
dc.DrawRectangle(Brushes.Transparent, null, new Rect(RenderSize));
if (this.startPoint.HasValue && this.endPoint.HasValue)
{
if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Line)
{
dc.DrawLine(rubberbandPen, this.startPoint.Value, this.endPoint.Value);
}
else if (this._service.DrawModeViewModel.GetDrawMode() == DrawMode.Ellipse)
{
var centerPoint = new Point((this.startPoint.Value.X + this.endPoint.Value.X) / 2, (this.startPoint.Value.Y + this.endPoint.Value.Y) / 2);
dc.DrawEllipse(Brushes.Transparent, rubberbandPen, centerPoint, Math.Abs(this.startPoint.Value.X - this.endPoint.Value.X) / 2, Math.Abs(this.startPoint.Value.Y - this.endPoint.Value.Y) / 2);
}
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.Polyline)
{
var disList = pointList.ToList();
for (int i = 1; i < pointList.Count; i++)
{
dc.DrawLine(rubberbandPen, disList[i - 1], disList[i]);
}
}
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
{
var disList = pointList.ToList();
for (int i = 1; i < pointList.Count; i++)
{
dc.DrawLine(rubberbandPen, disList[i - 1], disList[i]);
}
}
else
{
dc.DrawRectangle(Brushes.Transparent, rubberbandPen, new Rect(this.startPoint.Value, this.endPoint.Value));
}
}
}
private T GetParent<T>(Type parentType, DependencyObject dependencyObject) where T : DependencyObject
{
DependencyObject parent = VisualTreeHelper.GetParent(dependencyObject);
if (parent.GetType() == parentType)
return (T)parent;
return GetParent<T>(parentType, parent);
}
private void UpdateSelection()
{
IDiagramViewModel vm = (_designerCanvas.DataContext as IDiagramViewModel);
Rect rubberBand = new Rect(startPoint.Value, endPoint.Value);
ItemsControl itemsControl = GetParent<ItemsControl>(typeof(ItemsControl), _designerCanvas);
foreach (SelectableDesignerItemViewModelBase item in vm.Items)
{
if (item is SelectableDesignerItemViewModelBase)
{
DependencyObject container = itemsControl.ItemContainerGenerator.ContainerFromItem(item);
Rect itemRect = VisualTreeHelper.GetDescendantBounds((Visual)container);
Rect itemBounds = ((Visual)container).TransformToAncestor(_designerCanvas).TransformBounds(itemRect);
if (rubberBand.Contains(itemBounds))
{
//item.IsSelected = true;
vm.SelectionService.AddToSelection(item);
}
else
{
if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
{
//item.IsSelected = false;
vm.SelectionService.RemoveFromSelection(item);
}
}
}
}
}
}
}

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 AIStudio.Wpf.DiagramDesigner.Helpers;
namespace AIStudio.Wpf.DiagramDesigner
{
public static class DragAndDropProps
{
#region EnabledForDrag
public static readonly DependencyProperty EnabledForDragProperty =
DependencyProperty.RegisterAttached("EnabledForDrag", typeof(bool), typeof(DragAndDropProps),
new FrameworkPropertyMetadata((bool)false,
new PropertyChangedCallback(OnEnabledForDragChanged)));
public static bool GetEnabledForDrag(DependencyObject d)
{
return (bool)d.GetValue(EnabledForDragProperty);
}
public static void SetEnabledForDrag(DependencyObject d, bool value)
{
d.SetValue(EnabledForDragProperty, value);
}
private static void OnEnabledForDragChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement fe = (FrameworkElement) d;
if((bool)e.NewValue)
{
fe.PreviewMouseDown += Fe_PreviewMouseDown;
fe.MouseMove += Fe_MouseMove;
}
else
{
fe.PreviewMouseDown -= Fe_PreviewMouseDown;
fe.MouseMove -= Fe_MouseMove;
}
}
#endregion
#region DragStartPoint
public static readonly DependencyProperty DragStartPointProperty =
DependencyProperty.RegisterAttached("DragStartPoint", typeof(Point?), typeof(DragAndDropProps));
public static Point? GetDragStartPoint(DependencyObject d)
{
return (Point?)d.GetValue(DragStartPointProperty);
}
public static void SetDragStartPoint(DependencyObject d, Point? value)
{
d.SetValue(DragStartPointProperty, value);
}
#endregion
static void Fe_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
Point? dragStartPoint = GetDragStartPoint((DependencyObject)sender);
if (e.LeftButton != MouseButtonState.Pressed)
dragStartPoint = null;
if (dragStartPoint.HasValue)
{
DragObject dataObject = new DragObject();
dataObject.ContentType = (((FrameworkElement)sender).DataContext as ToolBoxData).Type;
dataObject.DesiredSize = new Size(65, 65);
dataObject.Icon = (((FrameworkElement)sender).DataContext as ToolBoxData).Icon;
dataObject.ColorViewModel = (((FrameworkElement)sender).DataContext as ToolBoxData).ColorViewModel;
dataObject.DesignerItem = (((FrameworkElement)sender).DataContext as ToolBoxData).Addition as DesignerItemBase;
DragDrop.DoDragDrop((DependencyObject)sender, dataObject, DragDropEffects.Copy);
e.Handled = true;
}
}
static void Fe_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
SetDragStartPoint((DependencyObject)sender, e.GetPosition((IInputElement)sender));
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public static class ItemConnectProps
{
#region EnabledForConnection
public static readonly DependencyProperty EnabledForConnectionProperty =
DependencyProperty.RegisterAttached("EnabledForConnection", typeof(bool), typeof(ItemConnectProps),
new FrameworkPropertyMetadata((bool)false,
new PropertyChangedCallback(OnEnabledForConnectionChanged)));
public static bool GetEnabledForConnection(DependencyObject d)
{
return (bool)d.GetValue(EnabledForConnectionProperty);
}
public static void SetEnabledForConnection(DependencyObject d, bool value)
{
d.SetValue(EnabledForConnectionProperty, value);
}
private static void OnEnabledForConnectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement fe = (FrameworkElement)d;
if ((bool)e.NewValue)
{
fe.MouseEnter += Fe_MouseEnter;
}
else
{
fe.MouseEnter -= Fe_MouseEnter;
}
}
#endregion
static void Fe_MouseEnter(object sender, MouseEventArgs e)
{
if (((FrameworkElement)sender).DataContext is DesignerItemViewModelBase)
{
DesignerItemViewModelBase designerItem = (DesignerItemViewModelBase)((FrameworkElement)sender).DataContext;
designerItem.ShowConnectors = true;
}
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public static class SelectionProps
{
#region EnabledForSelection
public static readonly DependencyProperty EnabledForSelectionProperty =
DependencyProperty.RegisterAttached("EnabledForSelection", typeof(bool), typeof(SelectionProps),
new FrameworkPropertyMetadata((bool)false,
new PropertyChangedCallback(OnEnabledForSelectionChanged)));
public static bool GetEnabledForSelection(DependencyObject d)
{
return (bool)d.GetValue(EnabledForSelectionProperty);
}
public static void SetEnabledForSelection(DependencyObject d, bool value)
{
d.SetValue(EnabledForSelectionProperty, value);
}
private static void OnEnabledForSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement fe = (FrameworkElement)d;
if ((bool)e.NewValue)
{
fe.PreviewMouseDown += Fe_PreviewMouseDown;
}
else
{
fe.PreviewMouseDown -= Fe_PreviewMouseDown;
}
}
#endregion
static void Fe_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
SelectableDesignerItemViewModelBase selectableDesignerItemViewModelBase =
(SelectableDesignerItemViewModelBase)((FrameworkElement)sender).DataContext;
if(selectableDesignerItemViewModelBase != null && selectableDesignerItemViewModelBase.IsHitTestVisible)
{
if ((Keyboard.Modifiers & (ModifierKeys.Shift | ModifierKeys.Control)) != ModifierKeys.None)
{
if ((Keyboard.Modifiers & (ModifierKeys.Shift)) != ModifierKeys.None)
{
selectableDesignerItemViewModelBase.IsSelected = !selectableDesignerItemViewModelBase.IsSelected;
}
if ((Keyboard.Modifiers & (ModifierKeys.Control)) != ModifierKeys.None)
{
selectableDesignerItemViewModelBase.IsSelected = !selectableDesignerItemViewModelBase.IsSelected;
}
}
else if (!selectableDesignerItemViewModelBase.IsSelected)
{
foreach (SelectableDesignerItemViewModelBase item in selectableDesignerItemViewModelBase.Parent.SelectedItems)
item.IsSelected = false;
selectableDesignerItemViewModelBase.Parent.SelectedItems.Clear();
//selectableDesignerItemViewModelBase.IsSelected = true;
selectableDesignerItemViewModelBase.Parent.SelectionService.AddToSelection(selectableDesignerItemViewModelBase);
}
}
}
}
}

View File

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

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 AIStudio.Wpf.DiagramDesigner.Controls
{
public class BorderResizeThumb : Thumb
{
#region ResizeMode
/// <summary>
/// BindingWidthAndHeight Dependency Property
/// </summary>
public static readonly DependencyProperty ResizeModeProperty =
DependencyProperty.Register("ResizeMode", typeof(ResizeMode), typeof(BorderResizeThumb),
new FrameworkPropertyMetadata(ResizeMode.Size));
/// <summary>
/// Gets or sets the BindingWidthAndHeight property. This dependency property
/// indicates if the ResizableItemsControl is in Composing mode.
/// </summary>
public ResizeMode ResizeMode
{
get { return (ResizeMode)GetValue(ResizeModeProperty); }
set { SetValue(ResizeModeProperty, value); }
}
#endregion
#region ResizeElement
/// <summary>
/// BindingWidthAndHeight Dependency Property
/// </summary>
public static readonly DependencyProperty ResizeElementProperty =
DependencyProperty.Register("ResizeElement", typeof(FrameworkElement), typeof(BorderResizeThumb),
new FrameworkPropertyMetadata(null));
/// <summary>
/// Gets or sets the BindingWidthAndHeight property. This dependency property
/// indicates if the ResizableItemsControl is in Composing mode.
/// </summary>
public FrameworkElement ResizeElement
{
get { return (FrameworkElement)GetValue(ResizeElementProperty); }
set { SetValue(ResizeElementProperty, value); }
}
#endregion
public BorderResizeThumb()
{
base.DragDelta += new DragDeltaEventHandler(ResizeThumb_DragDelta);
}
void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
if (ResizeElement == null) return;
if (ResizeMode == ResizeMode.Size)
{
switch (base.VerticalAlignment)
{
case VerticalAlignment.Top:
if (ResizeElement.Height - e.VerticalChange > ResizeElement.MinHeight && ResizeElement.Height - e.VerticalChange < ResizeElement.MaxHeight)
{
ResizeElement.Height -= e.VerticalChange;
}
break;
case VerticalAlignment.Bottom:
if (ResizeElement.Height + e.VerticalChange > ResizeElement.MinHeight && ResizeElement.Height + e.VerticalChange < ResizeElement.MaxHeight)
{
ResizeElement.Height += e.VerticalChange;
}
break;
default:
break;
}
switch (base.HorizontalAlignment)
{
case HorizontalAlignment.Left:
if (ResizeElement.Width - e.HorizontalChange > ResizeElement.MinWidth && ResizeElement.Width - e.HorizontalChange < ResizeElement.MaxWidth)
{
ResizeElement.Width -= e.HorizontalChange;
}
break;
case HorizontalAlignment.Right:
if (ResizeElement.Width + e.HorizontalChange > ResizeElement.MinWidth && ResizeElement.Width + e.HorizontalChange < ResizeElement.MaxWidth)
{
ResizeElement.Width += e.HorizontalChange;
}
break;
default:
break;
}
}
else if (ResizeMode == ResizeMode.Margin)
{
switch (base.VerticalAlignment)
{
case VerticalAlignment.Top:
if (ResizeElement.Margin.Top + e.VerticalChange > 0)
{
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left, ResizeElement.Margin.Top + e.VerticalChange, ResizeElement.Margin.Right, ResizeElement.Margin.Bottom);
}
break;
case VerticalAlignment.Bottom:
if (ResizeElement.Margin.Bottom - e.VerticalChange > 0)
{
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left, ResizeElement.Margin.Top, ResizeElement.Margin.Right, ResizeElement.Margin.Bottom - e.VerticalChange);
}
break;
default:
break;
}
switch (base.HorizontalAlignment)
{
case HorizontalAlignment.Left:
if (ResizeElement.Margin.Left + e.HorizontalChange > 0)
{
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left + e.HorizontalChange, ResizeElement.Margin.Top, ResizeElement.Margin.Right, ResizeElement.Margin.Bottom);
}
break;
case HorizontalAlignment.Right:
if (ResizeElement.Margin.Right - e.HorizontalChange > 0)
{
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left, ResizeElement.Margin.Top, ResizeElement.Margin.Right - e.HorizontalChange, ResizeElement.Margin.Bottom);
}
break;
default:
break;
}
}
else if (ResizeMode == ResizeMode.DragMargin)
{
ResizeElement.Margin = new Thickness(ResizeElement.Margin.Left + e.HorizontalChange, ResizeElement.Margin.Top + e.VerticalChange, ResizeElement.Margin.Right - e.HorizontalChange, ResizeElement.Margin.Bottom - e.VerticalChange);
}
}
}
public enum ResizeMode
{
Size,
Margin,
DragMargin,
}
}

View File

@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
/// <summary>
/// Provides a mechanism for constructing MenuItems
/// within a ViewModel
/// </summary>
/// <example>
/// <![CDATA[
///
/// AND IN VIEWMODEL C# DO THIS TO CREATE MENUS
/// private List<CinchMenuItem> CreateMenus()
/// {
/// var menu = new List<CinchMenuItem>();
/// //create the File Menu
/// var miFile = new CinchMenuItem("File");
/// var miExit = new CinchMenuItem("Exit");
/// miExit.Command = ExitApplicationCommand;
/// miFile.Children.Add(miExit);
/// menu.Add(miFile);
/// //create the Actions Menu
/// menu.Add(new CinchMenuItem("Actions"));
/// return menu;
/// }
///
///
/// public List<CinchMenuItem> MenuOptions
/// {
/// get
/// {
/// return CreateMenus();
/// }
/// }
///
/// AND IN XAML DO THE FOLLOWING FOR THE STYLE
/// <Style x:Key="ContextMenuItemStyle">
/// <Setter Property="MenuItem.Header" Value="{Binding Text}"/>
/// <Setter Property="MenuItem.ItemsSource" Value="{Binding Children}"/>
/// <Setter Property="MenuItem.Command" Value="{Binding Command}" />
/// <Setter Property="MenuItem.Icon" Value="{Binding Icon}" />
/// </Style>
///
/// AND YOU CAN CREATE A MENU LIKE THIS
/// <StackPanel Orientation="Horizontal">
/// <Image Source="{Binding Image}" Width="16" Height="16" />
/// <TextBlock Margin="5" HorizontalAlignment="Left" VerticalAlignment="Center"
/// Text="{Binding Header}" />
/// <StackPanel.ContextMenu>
/// <ContextMenu ItemContainerStyle="{StaticResource ContextMenuItemStyle}"
/// ItemsSource="{Binding MenuOptions}" />
/// </StackPanel.ContextMenu>
/// </StackPanel>
/// ]]>
/// </example>
public class CinchMenuItem
{
#region Public Properties
public String Text { get; set; }
public String IconUrl { get; set; }
public bool IsChecked { get; set; }
public bool IsCheckable { get; set; }
public List<CinchMenuItem> Children { get; private set; }
public Object CommandParameter { get; set; }
public SimpleCommand Command { get; set; }
#endregion
#region Ctor
public CinchMenuItem()
{
Children = new List<CinchMenuItem>();
}
public CinchMenuItem(string item)
{
Text = item;
Children = new List<CinchMenuItem>();
}
#endregion
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public class Connector : Control
{
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
DesignerCanvas canvas = GetDesignerCanvas(this);
if (canvas != null)
{
canvas.SourceConnector = this;
}
}
public ConnectorOrientation Orientation { get; set; }
// iterate through visual tree to get parent DesignerCanvas
private DesignerCanvas GetDesignerCanvas(DependencyObject element)
{
while (element != null && !(element is DesignerCanvas))
element = VisualTreeHelper.GetParent(element);
return element as DesignerCanvas;
}
}
}

View File

@@ -0,0 +1,516 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Xml;
using System.Linq;
using System.Windows.Shapes;
using System.Windows.Resources;
using System.Runtime.InteropServices;
namespace AIStudio.Wpf.DiagramDesigner
{
public class DesignerCanvas : Canvas
{
private IDiagramViewModel _viewModel { get { return DataContext as IDiagramViewModel; } }
private IDiagramServiceProvider _service { get { return DiagramServicesProvider.Instance.Provider; } }
private ConnectorViewModel partialConnection;
private List<Connector> connectorsHit = new List<Connector>();
private Point? rubberbandSelectionStartPoint = null;
#region GridCellSize
public static readonly DependencyProperty GridCellSizeProperty =
DependencyProperty.Register("GridCellSize",
typeof(Size),
typeof(DesignerCanvas),
new FrameworkPropertyMetadata(new Size(50, 50), FrameworkPropertyMetadataOptions.AffectsRender));
public Size GridCellSize
{
get { return (Size)GetValue(GridCellSizeProperty); }
set { SetValue(GridCellSizeProperty, value); }
}
#endregion
#region ShowGrid
public static readonly DependencyProperty ShowGridProperty =
DependencyProperty.Register("ShowGrid",
typeof(bool),
typeof(DesignerCanvas),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
public bool ShowGrid
{
get { return (bool)GetValue(ShowGridProperty); }
set { SetValue(ShowGridProperty, value); }
}
#endregion
#region GridColor
public static readonly DependencyProperty GridColorProperty =
DependencyProperty.Register("GridColor",
typeof(Color),
typeof(DesignerCanvas),
new FrameworkPropertyMetadata(Colors.LightGray, FrameworkPropertyMetadataOptions.AffectsRender));
public Color GridColor
{
get { return (Color)GetValue(GridColorProperty); }
set { SetValue(GridColorProperty, value); }
}
#endregion
#region GridMargin mm
public static readonly DependencyProperty GridMarginProperty =
DependencyProperty.Register("GridMargin",
typeof(double),
typeof(DesignerCanvas),
new FrameworkPropertyMetadata(28d, FrameworkPropertyMetadataOptions.AffectsRender));
public double GridMargin
{
get { return (double)GetValue(GridMarginProperty); }
set { SetValue(GridMarginProperty, value); }
}
#endregion
public DesignerCanvas()
{
this.AllowDrop = true;
Mediator.Instance.Register(this);
_service.PropertyChanged += _service_PropertyChanged;
}
protected override void OnRender(DrawingContext dc)
{
var rect = new Rect(0, 0, RenderSize.Width, RenderSize.Height);
dc.DrawRectangle(Background, null, rect);
if (ShowGrid && GridCellSize.Width > 0 && GridCellSize.Height > 0)
DrawGrid(dc, rect);
}
protected virtual void DrawGrid(DrawingContext dc, Rect rect)
{
//using .5 forces wpf to draw a single pixel line
for (var i = GridMargin + 0.5; i < rect.Height - GridMargin; i += GridCellSize.Height)
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(GridMargin, i), new Point(rect.Width - GridMargin, i));
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(GridMargin, rect.Height - GridMargin), new Point(rect.Width - GridMargin, rect.Height - GridMargin));
for (var i = GridMargin + 0.5; i < rect.Width - GridMargin; i += GridCellSize.Width)
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(i, GridMargin), new Point(i, rect.Height - GridMargin));
dc.DrawLine(new Pen(new SolidColorBrush(GridColor), 1), new Point(rect.Width - GridMargin, GridMargin), new Point(rect.Width - GridMargin, rect.Height - GridMargin));
}
private void _service_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (sender is IDrawModeViewModel)
{
if (e.PropertyName == nameof(CursorMode))
{
if (_service.DrawModeViewModel.CursorMode == CursorMode.Format)
{
EnterFormat();
}
else if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
{
EnterMove();
}
}
}
}
#region Format/Move
private void EnterFormat()
{
StreamResourceInfo sri = Application.GetResourceStream(new Uri("pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Images/FormatPainter.cur", UriKind.RelativeOrAbsolute));
this.Cursor = new Cursor(sri.Stream);
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
{
item.IsHitTestVisible = false;
}
}
private void EnterMove()
{
this.Cursor = Cursors.SizeAll;
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
{
item.IsHitTestVisible = false;
}
}
private void ExitCursor()
{
this.Cursor = Cursors.Arrow;
foreach (SelectableDesignerItemViewModelBase item in _viewModel.Items)
{
item.IsHitTestVisible = true;
}
_service.DrawModeViewModel.CursorMode = CursorMode.Normal;
}
#endregion
private void Format(SelectableDesignerItemViewModelBase source, SelectableDesignerItemViewModelBase target)
{
CopyHelper.CopyPropertyValue(source.ColorViewModel, target.ColorViewModel);
CopyHelper.CopyPropertyValue(source.FontViewModel, target.FontViewModel);
}
private Connector sourceConnector;
public Connector SourceConnector
{
get { return sourceConnector; }
set
{
if (sourceConnector != value)
{
sourceConnector = value;
connectorsHit.Add(sourceConnector);
FullyCreatedConnectorInfo sourceDataItem = sourceConnector.DataContext as FullyCreatedConnectorInfo;
Rect rectangleBounds = sourceConnector.TransformToVisual(this).TransformBounds(new Rect(sourceConnector.RenderSize));
Point point = new Point(rectangleBounds.Left + (rectangleBounds.Width / 2),
rectangleBounds.Bottom + (rectangleBounds.Height / 2));
partialConnection = new ConnectorViewModel(sourceDataItem, new PartCreatedConnectionInfo(point), _service.DrawModeViewModel.VectorLineDrawMode);
_viewModel.DirectAddItemCommand.Execute(partialConnection);
}
}
}
private FullyCreatedConnectorInfo sourceConnectorInfo;
public FullyCreatedConnectorInfo SourceConnectorInfo
{
get { return sourceConnectorInfo; }
set
{
if (sourceConnectorInfo != value)
{
sourceConnectorInfo = value;
sourceConnector = new Connector() { Name = "占位" };//占位使用
connectorsHit.Add(sourceConnector);
Rect rectangleBounds = new Rect(sourceConnectorInfo.DataItem.Left, sourceConnectorInfo.DataItem.Top, 3, 3);
Point point = new Point(rectangleBounds.Left + (rectangleBounds.Width / 2),
rectangleBounds.Bottom + (rectangleBounds.Height / 2));
partialConnection = new ConnectorViewModel(sourceConnectorInfo, new PartCreatedConnectionInfo(point), _service.DrawModeViewModel.VectorLineDrawMode);
_viewModel.DirectAddItemCommand.Execute(partialConnection);
}
}
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
if (_service.DrawModeViewModel.CursorMode == CursorMode.Format)
{
var element = (e.OriginalSource as FrameworkElement);
if (element.DataContext is SelectableDesignerItemViewModelBase target)
{
Format(_viewModel.SelectedItems.FirstOrDefault(), target);
return;
}
ExitCursor();
}
else if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
{
ExitCursor();
return;
}
if (e.LeftButton == MouseButtonState.Pressed)
{
//if we are source of event, we are rubberband selecting
if (e.Source == this)
{
// in case that this click is the start for a
// drag operation we cache the start point
rubberbandSelectionStartPoint = e.GetPosition(this);
IDiagramViewModel vm = (this.DataContext as IDiagramViewModel);
if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
{
vm.ClearSelectedItemsCommand.Execute(null);
}
e.Handled = true;
if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.ConnectingLine)
{
if (connectorsHit.Count == 0)
{
LinkPointDesignerItemViewModel pointItemView = new LinkPointDesignerItemViewModel(rubberbandSelectionStartPoint.Value);
_viewModel.DirectAddItemCommand.Execute(pointItemView);
SourceConnectorInfo = pointItemView.TopConnector;
}
}
}
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
Point currentPoint = e.GetPosition(this);
_viewModel.CurrentPoint = currentPoint;
var point = CursorPointManager.GetCursorPosition();
_viewModel.CurrentColor = ColorPickerManager.GetColor(point.X, point.Y);
if (_service.DrawModeViewModel.CursorMode == CursorMode.Move)
{
_viewModel.SelectedItems.OfType<DesignerItemViewModelBase>().ToList().ForEach(p =>
{
p.Left = currentPoint.X;
p.Top = currentPoint.Y;
});
return;
}
if (SourceConnector != null)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
partialConnection.SinkConnectorInfo = new PartCreatedConnectionInfo(currentPoint);
HitTesting(currentPoint);
}
}
else
{
// if mouse button is not pressed we have no drag operation, ...
if (e.LeftButton != MouseButtonState.Pressed && _service.DrawModeViewModel.GetDrawMode() != DrawMode.DirectLine)
rubberbandSelectionStartPoint = null;
// ... but if mouse button is pressed and start
// point value is set we do have one
if (this.rubberbandSelectionStartPoint.HasValue)
{
// create rubberband adorner
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this);
if (adornerLayer != null)
{
RubberbandAdorner adorner = new RubberbandAdorner(this, rubberbandSelectionStartPoint);
if (adorner != null)
{
adornerLayer.Add(adorner);
}
}
}
}
e.Handled = true;
}
protected override void OnMouseUp(MouseButtonEventArgs e)
{
base.OnMouseUp(e);
if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.DirectLine)
{
return;
}
Mediator.Instance.NotifyColleagues<bool>("DoneDrawingMessage", true);
if (sourceConnector != null)
{
FullyCreatedConnectorInfo sourceDataItem = sourceConnectorInfo ?? (sourceConnector.DataContext as FullyCreatedConnectorInfo);
if (connectorsHit.Count() == 2)
{
Connector sinkConnector = connectorsHit.Last();
FullyCreatedConnectorInfo sinkDataItem = sinkConnector.DataContext as FullyCreatedConnectorInfo;
int indexOfLastTempConnection = sinkDataItem.DataItem.Parent.Items.Count - 1;
sinkDataItem.DataItem.Parent.DirectRemoveItemCommand.Execute(
sinkDataItem.DataItem.Parent.Items[indexOfLastTempConnection]);
sinkDataItem.DataItem.Parent.AddItemCommand.Execute(new ConnectorViewModel(sourceDataItem, sinkDataItem, _service.DrawModeViewModel.VectorLineDrawMode));
}
else if (_service.DrawModeViewModel.GetDrawMode() == DrawMode.ConnectingLine && connectorsHit.Count() == 1)
{
LinkPointDesignerItemViewModel pointItemView = new LinkPointDesignerItemViewModel(e.GetPosition(this));
FullyCreatedConnectorInfo sinkDataItem = pointItemView.TopConnector;
int indexOfLastTempConnection = _viewModel.Items.Count - 1;
_viewModel.DirectRemoveItemCommand.Execute(_viewModel.Items[indexOfLastTempConnection]);
_viewModel.DirectAddItemCommand.Execute(pointItemView);
var connector = new ConnectorViewModel(sourceDataItem, sinkDataItem, _service.DrawModeViewModel.VectorLineDrawMode);
_viewModel.AddItemCommand.Execute(connector);
sourceDataItem.DataItem.ZIndex++;
connector.ZIndex--;
}
else
{
//Need to remove last item as we did not finish drawing the path
int indexOfLastTempConnection = sourceDataItem.DataItem.Parent.Items.Count - 1;
sourceDataItem.DataItem.Parent.DirectRemoveItemCommand.Execute(
sourceDataItem.DataItem.Parent.Items[indexOfLastTempConnection]);
}
}
connectorsHit = new List<Connector>();
sourceConnector = null;
sourceConnectorInfo = null;
_service.DrawModeViewModel.ResetDrawMode();
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if (e.Key == Key.Left)
{
if (_viewModel.SelectedItems != null)
{
foreach(var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Left -= 0.1;
}
}
}
else if (e.Key == Key.Right)
{
if (_viewModel.SelectedItems != null)
{
foreach (var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Left += 0.1;
}
}
}
else if (e.Key == Key.Up)
{
if (_viewModel.SelectedItems != null)
{
foreach (var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Top -= 0.1;
}
}
}
else if (e.Key == Key.Down)
{
if (_viewModel.SelectedItems != null)
{
foreach (var item in _viewModel.SelectedItems.OfType<DesignerItemViewModelBase>())
{
item.Top += 0.1;
}
}
}
}
protected override Size MeasureOverride(Size constraint)
{
Size size = new Size();
foreach (UIElement element in this.InternalChildren)
{
double left = Canvas.GetLeft(element);
double top = Canvas.GetTop(element);
left = double.IsNaN(left) ? 0 : left;
top = double.IsNaN(top) ? 0 : top;
//measure desired size for each child
element.Measure(constraint);
Size desiredSize = element.DesiredSize;
if (!double.IsNaN(desiredSize.Width) && !double.IsNaN(desiredSize.Height))
{
size.Width = Math.Max(size.Width, left + desiredSize.Width);
size.Height = Math.Max(size.Height, top + desiredSize.Height);
}
}
// add margin
size.Width += 10;
size.Height += 10;
return size;
}
private void HitTesting(Point hitPoint)
{
DependencyObject hitObject = this.InputHitTest(hitPoint) as DependencyObject;
while (hitObject != null &&
hitObject.GetType() != typeof(DesignerCanvas))
{
if (hitObject is Connector)
{
if (connectorsHit.Any(p => p.Name == "占位"))
{
connectorsHit.Remove(connectorsHit.FirstOrDefault(p => p.Name == "占位"));
}
if (!connectorsHit.Contains(hitObject as Connector))
connectorsHit.Add(hitObject as Connector);
}
hitObject = VisualTreeHelper.GetParent(hitObject);
}
}
protected override void OnDrop(DragEventArgs e)
{
base.OnDrop(e);
DragObject dragObject = e.Data.GetData(typeof(DragObject)) as DragObject;
if (dragObject != null)
{
(DataContext as IDiagramViewModel).ClearSelectedItemsCommand.Execute(null);
Point position = e.GetPosition(this);
DesignerItemViewModelBase itemBase = null;
if (dragObject.DesignerItem != null)
{
itemBase = (DesignerItemViewModelBase)Activator.CreateInstance(dragObject.ContentType, null, dragObject.DesignerItem);
}
else
{
itemBase = (DesignerItemViewModelBase)Activator.CreateInstance(dragObject.ContentType);
itemBase.Icon = dragObject.Icon;
itemBase.ColorViewModel = CopyHelper.Mapper(dragObject.ColorViewModel);
}
itemBase.Left = Math.Max(0, position.X - itemBase.ItemWidth / 2);
itemBase.Top = Math.Max(0, position.Y - itemBase.ItemHeight / 2);
(DataContext as IDiagramViewModel).AddItemCommand.Execute(itemBase);
}
var dragFile = e.Data.GetData(DataFormats.FileDrop);
if (dragFile != null && dragFile is string[] files)
{
foreach (var file in files)
{
(DataContext as IDiagramViewModel).ClearSelectedItemsCommand.Execute(null);
Point position = e.GetPosition(this);
ImageItemViewModel itemBase = new ImageItemViewModel();
itemBase.Icon = file;
itemBase.Suffix = System.IO.Path.GetExtension(itemBase.Icon).ToLower();
itemBase.InitWidthAndHeight();
itemBase.AutoSize();
itemBase.Left = Math.Max(0, position.X - itemBase.ItemWidth / 2);
itemBase.Top = Math.Max(0, position.Y - itemBase.ItemHeight / 2);
(DataContext as IDiagramViewModel).AddItemCommand.Execute(itemBase);
}
}
e.Handled = true;
}
}
}

View File

@@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace AIStudio.Wpf.DiagramDesigner.Controls
{
public class DragThumb : Thumb
{
public DragThumb()
{
base.DragDelta += new DragDeltaEventHandler(DragThumb_DragDelta);
base.DragStarted += DragThumb_DragStarted;
base.DragCompleted += DragThumb_DragCompleted;
}
private List<SelectableDesignerItemViewModelBase> designerItems;
private void DragThumb_DragStarted(object sender, DragStartedEventArgs e)
{
SelectableDesignerItemViewModelBase designerItem = this.DataContext as SelectableDesignerItemViewModelBase;
if (designerItem != null && designerItem.IsSelected)
{
// we only move DesignerItems
designerItems = designerItem.SelectedItems.ToList();
if (designerItem is ConnectorViewModel connector)
{
designerItems.Add(connector.SourceConnectorInfo.DataItem);
designerItems.Add((connector.SinkConnectorInfo as FullyCreatedConnectorInfo).DataItem);
if (designerItem.OutTextItem != null)
{
designerItems.Remove(designerItem.OutTextItem);//这个自动计算位置
}
}
if (designerItem is PointDesignerItemViewModel)
{
designerItems = new List<SelectableDesignerItemViewModelBase> { designerItem };
}
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
{
item.BeginDo = true;
item.SetOldValue(item.Left, nameof(item.Left));
item.SetOldValue(item.Top, nameof(item.Top));
}
e.Handled = true;
}
else
{
designerItems = null;
}
}
private void DragThumb_DragCompleted(object sender, DragCompletedEventArgs e)
{
if (designerItems != null)
{
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
{
item.SetCellAlignment();
item.BeginDo = false;
item.RaiseTopLeft();
}
e.Handled = true;
}
}
void DragThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
if (designerItems != null)
{
double minLeft = double.MaxValue;
double minTop = double.MaxValue;
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
{
double left = item.Left;
double top = item.Top;
minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);
minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);
double deltaHorizontal = Math.Max(-minLeft, e.HorizontalChange);
double deltaVertical = Math.Max(-minTop, e.VerticalChange);
item.Left += deltaHorizontal;
item.Top += deltaVertical;
}
e.Handled = true;
}
}
private DesignerCanvas GetDesignerCanvas(DependencyObject element)
{
while (element != null && !(element is DesignerCanvas))
element = VisualTreeHelper.GetParent(element);
return element as DesignerCanvas;
}
}
}

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

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
namespace AIStudio.Wpf.DiagramDesigner.Controls
{
public class PointDragThumb : Thumb
{
public PointDragThumb()
{
base.DragDelta += new DragDeltaEventHandler(DragThumb_DragDelta);
base.DragStarted += DragThumb_DragStarted;
base.DragCompleted += DragThumb_DragCompleted;
}
private void DragThumb_DragStarted(object sender, DragStartedEventArgs e)
{
}
private void DragThumb_DragCompleted(object sender, DragCompletedEventArgs e)
{
}
void DragThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
if (this.DataContext is PointInfoBase point)
{
double minLeft = double.MaxValue;
double minTop = double.MaxValue;
double left = point.X;
double top = point.Y;
minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);
minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);
double deltaHorizontal = Math.Max(-minLeft, e.HorizontalChange);
double deltaVertical = Math.Max(-minTop, e.VerticalChange);
point.X += deltaHorizontal;
point.Y += deltaVertical;
}
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public class RelativePositionPanel : Panel
{
public static readonly DependencyProperty RelativePositionProperty =
DependencyProperty.RegisterAttached("RelativePosition", typeof(Point), typeof(RelativePositionPanel),
new FrameworkPropertyMetadata(new Point(0, 0),
new PropertyChangedCallback(RelativePositionPanel.OnRelativePositionChanged)));
public static Point GetRelativePosition(UIElement element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (Point)element.GetValue(RelativePositionProperty);
}
public static void SetRelativePosition(UIElement element, Point value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(RelativePositionProperty, value);
}
private static void OnRelativePositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement reference = d as UIElement;
if (reference != null)
{
RelativePositionPanel parent = VisualTreeHelper.GetParent(reference) as RelativePositionPanel;
if (parent != null)
{
parent.InvalidateArrange();
}
}
}
protected override Size ArrangeOverride(Size arrangeSize)
{
foreach (UIElement element in base.InternalChildren)
{
if (element != null)
{
Point relPosition = GetRelativePosition(element);
double x = (arrangeSize.Width - element.DesiredSize.Width) * relPosition.X;
double y = (arrangeSize.Height - element.DesiredSize.Height) * relPosition.Y;
if (double.IsNaN(x)) x = 0;
if (double.IsNaN(y)) y = 0;
element.Arrange(new Rect(new Point(x, y), element.DesiredSize));
}
}
return arrangeSize;
}
protected override Size MeasureOverride(Size availableSize)
{
Size size = new Size(double.PositiveInfinity, double.PositiveInfinity);
// SDK docu says about InternalChildren Property: 'Classes that are derived from Panel
// should use this property, instead of the Children property, for internal overrides
// such as MeasureCore and ArrangeCore.
foreach (UIElement element in this.InternalChildren)
{
if (element != null)
element.Measure(size);
}
return base.MeasureOverride(availableSize);
}
}
}

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 AIStudio.Wpf.DiagramDesigner.Controls
{
public class ResizeThumb : Thumb
{
public ResizeThumb()
{
base.DragDelta += new DragDeltaEventHandler(ResizeThumb_DragDelta);
base.DragStarted += ResizeThumb_DragStarted;
base.DragCompleted += ResizeThumb_DragCompleted;
}
private List<SelectableDesignerItemViewModelBase> designerItems;
IDiagramViewModel diagarmViewModel;
private void ResizeThumb_DragStarted(object sender, DragStartedEventArgs e)
{
DesignerItemViewModelBase designerItem = this.DataContext as DesignerItemViewModelBase;
diagarmViewModel = designerItem.Parent;
if (designerItem != null && designerItem.IsSelected)
{
designerItems = designerItem.SelectedItems.ToList();
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
{
item.BeginDo = true;
item.SetOldValue(item.ItemWidth, nameof(item.ItemWidth));
item.SetOldValue(item.ItemHeight, nameof(item.ItemHeight));
}
e.Handled = true;
}
else
{
designerItems = null;
}
}
private void ResizeThumb_DragCompleted(object sender, DragCompletedEventArgs e)
{
if (designerItems != null)
{
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
{
item.BeginDo = false;
item.RaiseItemWidthHeight();
}
e.Handled = true;
}
}
void ResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
if (designerItems != null)
{
double minLeft, minTop, minDeltaHorizontal, minDeltaVertical;
double dragDeltaVertical, dragDeltaHorizontal, scale;
CalculateDragLimits(designerItems.OfType<DesignerItemViewModelBase>(), out minLeft, out minTop,
out minDeltaHorizontal, out minDeltaVertical);
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
{
if (item != null && item.ParentId == Guid.Empty)
{
switch (base.VerticalAlignment)
{
case VerticalAlignment.Bottom:
dragDeltaVertical = Math.Min(-e.VerticalChange, minDeltaVertical);
scale = (item.ItemHeight - dragDeltaVertical) / item.ItemHeight;
DragBottom(scale, item, diagarmViewModel.SelectionService);
break;
case VerticalAlignment.Top:
double top = item.Top;
dragDeltaVertical = Math.Min(Math.Max(-minTop, e.VerticalChange), minDeltaVertical);
scale = (item.ItemHeight - dragDeltaVertical) / item.ItemHeight;
DragTop(scale, item, diagarmViewModel.SelectionService);
break;
default:
break;
}
switch (base.HorizontalAlignment)
{
case HorizontalAlignment.Left:
double left = item.Left;
dragDeltaHorizontal = Math.Min(Math.Max(-minLeft, e.HorizontalChange), minDeltaHorizontal);
scale = (item.ItemWidth - dragDeltaHorizontal) / item.ItemWidth;
DragLeft(scale, item, diagarmViewModel.SelectionService);
break;
case HorizontalAlignment.Right:
dragDeltaHorizontal = Math.Min(-e.HorizontalChange, minDeltaHorizontal);
scale = (item.ItemWidth - dragDeltaHorizontal) / item.ItemWidth;
DragRight(scale, item, diagarmViewModel.SelectionService);
break;
default:
break;
}
}
}
e.Handled = true;
}
}
#region Helper methods
private void DragLeft(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
{
IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
double groupLeft = item.Left + item.ItemWidth;
foreach (DesignerItemViewModelBase groupItem in groupItems)
{
double groupItemLeft = groupItem.Left;
double delta = (groupLeft - groupItemLeft) * (scale - 1);
groupItem.Left = groupItemLeft - delta;
groupItem.ItemWidth = groupItem.ItemWidth * scale;
}
}
private void DragTop(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
{
IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
double groupBottom = item.Top + item.ItemHeight;
foreach (DesignerItemViewModelBase groupItem in groupItems)
{
double groupItemTop = groupItem.Top;
double delta = (groupBottom - groupItemTop) * (scale - 1);
groupItem.Top = groupItemTop - delta;
groupItem.ItemHeight = groupItem.ItemHeight * scale;
}
}
private void DragRight(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
{
IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
double groupLeft = item.Left;
foreach (DesignerItemViewModelBase groupItem in groupItems)
{
double groupItemLeft = groupItem.Left;
double delta = (groupItemLeft - groupLeft) * (scale - 1);
groupItem.Left = groupItemLeft + delta;
groupItem.ItemWidth = groupItem.ItemWidth * scale;
}
}
private void DragBottom(double scale, DesignerItemViewModelBase item, SelectionService selectionService)
{
IEnumerable<DesignerItemViewModelBase> groupItems = selectionService.GetGroupMembers(item).Cast<DesignerItemViewModelBase>();
double groupTop = item.Top;
foreach (DesignerItemViewModelBase groupItem in groupItems)
{
double groupItemTop = groupItem.Top;
double delta = (groupItemTop - groupTop) * (scale - 1);
groupItem.Top = groupItemTop + delta;
groupItem.ItemHeight = groupItem.ItemHeight * scale;
}
}
private void CalculateDragLimits(IEnumerable<DesignerItemViewModelBase> selectedItems, out double minLeft, out double minTop, out double minDeltaHorizontal, out double minDeltaVertical)
{
minLeft = double.MaxValue;
minTop = double.MaxValue;
minDeltaHorizontal = double.MaxValue;
minDeltaVertical = double.MaxValue;
// drag limits are set by these parameters: canvas top, canvas left, minHeight, minWidth
// calculate min value for each parameter for each item
foreach (DesignerItemViewModelBase item in selectedItems)
{
double left = item.Left;
double top = item.Top;
minLeft = double.IsNaN(left) ? 0 : Math.Min(left, minLeft);
minTop = double.IsNaN(top) ? 0 : Math.Min(top, minTop);
minDeltaVertical = Math.Min(minDeltaVertical, 10);
minDeltaHorizontal = Math.Min(minDeltaHorizontal, 10);
}
}
#endregion
}
}

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 AIStudio.Wpf.DiagramDesigner.Controls
{
public class RotateThumb : Thumb
{
private Point centerPoint;
private Vector startVector;
private double initialAngle;
private Canvas designerCanvas;
private DesignerItemViewModelBase designerItem;
private RotateTransform rotateTransform;
public RotateThumb()
{
DragDelta += RotateThumb_DragDelta;
DragStarted += RotateThumb_DragStarted;
DragCompleted += RotateThumb_DragCompleted;
}
private List<SelectableDesignerItemViewModelBase> designerItems;
private void RotateThumb_DragStarted(object sender, DragStartedEventArgs e)
{
this.designerItem = this.DataContext as DesignerItemViewModelBase;
if (this.designerItem != null)
{
designerItems = designerItem.SelectedItems.ToList();
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
{
item.BeginDo = true;
item.SetOldValue(this.designerItem.Angle, nameof(this.designerItem.Angle));
}
this.designerCanvas = GetDesignerCanvas(this);
if (this.designerCanvas != null)
{
this.centerPoint =
new Point(this.designerItem.Left + this.designerItem.ItemWidth * 0.5,
this.designerItem.Top + this.designerItem.ItemHeight * 0.5);
Point startPoint = Mouse.GetPosition(this.designerCanvas);
this.startVector = Point.Subtract(startPoint, this.centerPoint);
this.initialAngle = this.designerItem.Angle;
}
e.Handled = true;
}
else
{
designerItems = null;
}
}
private void RotateThumb_DragCompleted(object sender, DragCompletedEventArgs e)
{
this.designerItem = this.DataContext as DesignerItemViewModelBase;
if (this.designerItems != null)
{
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
{
item.BeginDo = false;
item.RaiseAngle();
}
e.Handled = true;
}
}
private void RotateThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
if (this.designerItems != null && this.designerCanvas != null)
{
Point currentPoint = Mouse.GetPosition(this.designerCanvas);
Vector deltaVector = Point.Subtract(currentPoint, this.centerPoint);
double angle = Vector.AngleBetween(this.startVector, deltaVector);
foreach (DesignerItemViewModelBase item in designerItems.OfType<DesignerItemViewModelBase>())
{
item.Angle = this.initialAngle + Math.Round(angle, 0);
}
e.Handled = true;
}
}
private DesignerCanvas GetDesignerCanvas(DependencyObject element)
{
while (element != null && !(element is DesignerCanvas))
element = VisualTreeHelper.GetParent(element);
return element as DesignerCanvas;
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public class ZoomBox : Control
{
private Thumb zoomThumb;
private Canvas zoomCanvas;
private Slider zoomSlider;
private ScaleTransform scaleTransform;
#region DPs
#region ScrollViewer
public ScrollViewer ScrollViewer
{
get { return (ScrollViewer)GetValue(ScrollViewerProperty); }
set { SetValue(ScrollViewerProperty, value); }
}
public static readonly DependencyProperty ScrollViewerProperty =
DependencyProperty.Register("ScrollViewer", typeof(ScrollViewer), typeof(ZoomBox));
#endregion
#region DesignerCanvas
public static readonly DependencyProperty DesignerCanvasProperty =
DependencyProperty.Register("DesignerCanvas", typeof(DesignerCanvas), typeof(ZoomBox),
new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(OnDesignerCanvasChanged)));
public DesignerCanvas DesignerCanvas
{
get { return (DesignerCanvas)GetValue(DesignerCanvasProperty); }
set { SetValue(DesignerCanvasProperty, value); }
}
private static void OnDesignerCanvasChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ZoomBox target = (ZoomBox)d;
DesignerCanvas oldDesignerCanvas = (DesignerCanvas)e.OldValue;
DesignerCanvas newDesignerCanvas = target.DesignerCanvas;
target.OnDesignerCanvasChanged(oldDesignerCanvas, newDesignerCanvas);
}
protected virtual void OnDesignerCanvasChanged(DesignerCanvas oldDesignerCanvas, DesignerCanvas newDesignerCanvas)
{
if (oldDesignerCanvas != null)
{
newDesignerCanvas.LayoutUpdated -= new EventHandler(this.DesignerCanvas_LayoutUpdated);
newDesignerCanvas.MouseWheel -= new MouseWheelEventHandler(this.DesignerCanvas_MouseWheel);
}
if (newDesignerCanvas != null)
{
newDesignerCanvas.LayoutUpdated += new EventHandler(this.DesignerCanvas_LayoutUpdated);
newDesignerCanvas.MouseWheel += new MouseWheelEventHandler(this.DesignerCanvas_MouseWheel);
newDesignerCanvas.LayoutTransform = this.scaleTransform;
}
}
#endregion
#endregion
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (this.ScrollViewer == null)
return;
this.zoomThumb = Template.FindName("PART_ZoomThumb", this) as Thumb;
if (this.zoomThumb == null)
throw new Exception("PART_ZoomThumb template is missing!");
this.zoomCanvas = Template.FindName("PART_ZoomCanvas", this) as Canvas;
if (this.zoomCanvas == null)
throw new Exception("PART_ZoomCanvas template is missing!");
this.zoomSlider = Template.FindName("PART_ZoomSlider", this) as Slider;
if (this.zoomSlider == null)
throw new Exception("PART_ZoomSlider template is missing!");
this.zoomThumb.DragDelta += new DragDeltaEventHandler(this.Thumb_DragDelta);
this.zoomSlider.ValueChanged += new RoutedPropertyChangedEventHandler<double>(this.ZoomSlider_ValueChanged);
this.scaleTransform = new ScaleTransform();
}
private void ZoomSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
double scale = e.NewValue / e.OldValue;
double halfViewportHeight = this.ScrollViewer.ViewportHeight / 2;
double newVerticalOffset = ((this.ScrollViewer.VerticalOffset + halfViewportHeight) * scale - halfViewportHeight);
double halfViewportWidth = this.ScrollViewer.ViewportWidth / 2;
double newHorizontalOffset = ((this.ScrollViewer.HorizontalOffset + halfViewportWidth) * scale - halfViewportWidth);
this.scaleTransform.ScaleX *= scale;
this.scaleTransform.ScaleY *= scale;
this.ScrollViewer.ScrollToHorizontalOffset(newHorizontalOffset);
this.ScrollViewer.ScrollToVerticalOffset(newVerticalOffset);
}
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
double scale, xOffset, yOffset;
this.InvalidateScale(out scale, out xOffset, out yOffset);
this.ScrollViewer.ScrollToHorizontalOffset(this.ScrollViewer.HorizontalOffset + e.HorizontalChange / scale);
this.ScrollViewer.ScrollToVerticalOffset(this.ScrollViewer.VerticalOffset + e.VerticalChange / scale);
}
private void DesignerCanvas_LayoutUpdated(object sender, EventArgs e)
{
//htzk
try
{
double scale, xOffset, yOffset;
this.InvalidateScale(out scale, out xOffset, out yOffset);
this.zoomThumb.Width = this.ScrollViewer.ViewportWidth * scale;
this.zoomThumb.Height = this.ScrollViewer.ViewportHeight * scale;
Canvas.SetLeft(this.zoomThumb, xOffset + this.ScrollViewer.HorizontalOffset * scale);
Canvas.SetTop(this.zoomThumb, yOffset + this.ScrollViewer.VerticalOffset * scale);
}
catch { }
}
private void DesignerCanvas_MouseWheel(object sender, EventArgs e)
{
MouseWheelEventArgs wheel = (MouseWheelEventArgs)e;
//divide the value by 10 so that it is more smooth
double value = Math.Max(0, wheel.Delta / 10);
value = Math.Min(wheel.Delta, 10);
this.zoomSlider.Value += value;
}
private void InvalidateScale(out double scale, out double xOffset, out double yOffset)
{
double w = DesignerCanvas.ActualWidth * this.scaleTransform.ScaleX;
double h = DesignerCanvas.ActualHeight * this.scaleTransform.ScaleY;
// zoom canvas size
double x = this.zoomCanvas.ActualWidth;
double y = this.zoomCanvas.ActualHeight;
double scaleX = x / w;
double scaleY = y / h;
scale = (scaleX < scaleY) ? scaleX : scaleY;
xOffset = (x - scale * w) / 2;
yOffset = (y - scale * h) / 2;
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Windows.Data;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ArrowPathConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is ArrowPathStyle arrowStyle)
{
return ArrowPathData.Arrow[(int)arrowStyle];
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Windows.Data;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ArrowSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is ArrowSizeStyle arrowStyle)
{
return (int)arrowStyle;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BoolToVisibilityConverter : IValueConverter
{
static BoolToVisibilityConverter()
{
Instance = new BoolToVisibilityConverter();
}
public static BoolToVisibilityConverter Instance
{
get;
private set;
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value) ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public class ClipConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string para = parameter?.ToString();
try
{
if (value is ImageItemViewModel imageItemViewModel)
{
double xradio = imageItemViewModel.ItemWidth / imageItemViewModel.ImageWidth;
double yradio = imageItemViewModel.ItemHeight / imageItemViewModel.ImageHeight;
if (para == "Clip")
{
if (imageItemViewModel.ClipMode == ClipMode.RectangleGeometry)
{
RectangleGeometry rectangle = new RectangleGeometry();
if (imageItemViewModel.ResizeMode == false)
{
rectangle.Rect = new System.Windows.Rect(imageItemViewModel.ResizeMargin.Left * xradio, imageItemViewModel.ResizeMargin.Top * yradio, imageItemViewModel.ItemWidth, imageItemViewModel.ItemHeight);
}
else
{
rectangle.Rect = new System.Windows.Rect(imageItemViewModel.ResizeMargin.Left, imageItemViewModel.ResizeMargin.Top , imageItemViewModel.ItemWidth - (imageItemViewModel.ResizeMargin.Left + imageItemViewModel.ResizeMargin.Right), imageItemViewModel.ItemHeight - (imageItemViewModel.ResizeMargin.Top + imageItemViewModel.ResizeMargin.Bottom));
}
return rectangle;
}
else if (imageItemViewModel.ClipMode == ClipMode.EllipseGeometry)
{
EllipseGeometry ellipse = new EllipseGeometry();
if (imageItemViewModel.ResizeMode == false)
{
ellipse.Center = new Point(imageItemViewModel.ResizeMargin.Left * xradio + imageItemViewModel.ItemWidth / 2, imageItemViewModel.ResizeMargin.Top * yradio + imageItemViewModel.ItemHeight / 2);
ellipse.RadiusX = imageItemViewModel.ItemWidth / 2;
ellipse.RadiusY = imageItemViewModel.ItemHeight / 2;
}
else
{
ellipse.Center = new Point(imageItemViewModel.ResizeMargin.Left + (imageItemViewModel.ItemWidth - imageItemViewModel.ResizeMargin.Left - imageItemViewModel.ResizeMargin.Right) / 2, imageItemViewModel.ResizeMargin.Top + (imageItemViewModel.ItemHeight - imageItemViewModel.ResizeMargin.Top - imageItemViewModel.ResizeMargin.Bottom)/ 2);
ellipse.RadiusX = (imageItemViewModel.ItemWidth - imageItemViewModel.ResizeMargin.Left - imageItemViewModel.ResizeMargin.Right) / 2;
ellipse.RadiusY = (imageItemViewModel.ItemHeight - imageItemViewModel.ResizeMargin.Top - imageItemViewModel.ResizeMargin.Bottom) / 2;
}
return ellipse;
}
}
else if (para == "Margin")
{
if (imageItemViewModel.ResizeMode == false)
{
return new Thickness(-imageItemViewModel.ResizeMargin.Left * xradio, -imageItemViewModel.ResizeMargin.Top * yradio, -imageItemViewModel.ResizeMargin.Right * xradio, -imageItemViewModel.ResizeMargin.Bottom * yradio);
}
else
{
return new Thickness();
}
}
}
}
catch { }
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public class ColorBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Brush brush = null;
if (value is Color)
{
brush = new SolidColorBrush((Color)value);
}
else if (value is ColorObject colorObject)
{
if (colorObject.BrushType == BrushType.None)
brush = new SolidColorBrush(Colors.Transparent);
else if (colorObject.BrushType == BrushType.SolidColorBrush)
brush = new SolidColorBrush(colorObject.Color);
else if (colorObject.BrushType == BrushType.LinearGradientBrush)
{
Point startPoint;
Point endPoint;
if (colorObject.LinearOrientation == LinearOrientation.LeftToRight)
{
startPoint = new Point(0, 0.5);
endPoint = new Point(1, 0.5);
}
else if (colorObject.LinearOrientation == LinearOrientation.LeftTopToRightBottom)
{
startPoint = new Point(0, 0);
endPoint = new Point(1, 1);
}
else if (colorObject.LinearOrientation == LinearOrientation.TopToBottom)
{
startPoint = new Point(0.5, 0);
endPoint = new Point(0.5, 1);
}
else if (colorObject.LinearOrientation == LinearOrientation.RightTopToLeftBottom)
{
startPoint = new Point(1, 0);
endPoint = new Point(0, 1);
}
else if (colorObject.LinearOrientation == LinearOrientation.RightToLeft)
{
startPoint = new Point(1, 0.5);
endPoint = new Point(0, 0.5);
}
else if (colorObject.LinearOrientation == LinearOrientation.RightBottomToLeftTop)
{
startPoint = new Point(1, 1);
endPoint = new Point(0, 0);
}
else if (colorObject.LinearOrientation == LinearOrientation.BottomToTop)
{
startPoint = new Point(0.5, 1);
endPoint = new Point(0.5, 0);
}
else if (colorObject.LinearOrientation == LinearOrientation.LeftBottomToRightTop)
{
startPoint = new Point(0, 1);
endPoint = new Point(1, 0);
}
else
{
startPoint = new Point(0, 0.5);
endPoint = new Point(1, 0.5);
}
LinearGradientBrush myBrush = new LinearGradientBrush();
myBrush.StartPoint = startPoint;
myBrush.EndPoint = endPoint;
if (colorObject.GradientStop != null)
{
foreach (var stop in colorObject.GradientStop)
{
myBrush.GradientStops.Add(new System.Windows.Media.GradientStop(stop.Color, stop.Offset));
}
}
brush = myBrush;
RotateTransform rotateTransform = new RotateTransform(colorObject.Angle, 0.5, 0.5);
myBrush.RelativeTransform = rotateTransform;
}
else if (colorObject.BrushType == BrushType.RadialGradientBrush)
{
Point center;
Point gradientOrigin;
double radiusX;
double radiusY;
if (colorObject.RadialOrientation == RadialOrientation.LeftTop)
{
center = new Point(0, 0);
gradientOrigin = center;
radiusX = 1;
radiusY = 1;
}
else if (colorObject.RadialOrientation == RadialOrientation.RightTop)
{
center = new Point(1, 0);
gradientOrigin = center;
radiusX = 1;
radiusY = 1;
}
else if (colorObject.RadialOrientation == RadialOrientation.RightBottom)
{
center = new Point(1, 1);
gradientOrigin = center;
radiusX = 1;
radiusY = 1;
}
else if (colorObject.RadialOrientation == RadialOrientation.LeftBottom)
{
center = new Point(0, 1);
gradientOrigin = center;
radiusX = 1;
radiusY = 1;
}
else
{
center = new Point(0.5, 0.5);
gradientOrigin = center;
radiusX = 0.5;
radiusY = 0.5;
}
RadialGradientBrush myBrush = new RadialGradientBrush();
myBrush.Center = center;
myBrush.GradientOrigin = gradientOrigin;
myBrush.RadiusX = radiusX;
myBrush.RadiusY = radiusY;
if (colorObject.GradientStop != null)
{
foreach (var stop in colorObject.GradientStop)
{
myBrush.GradientStops.Add(new System.Windows.Media.GradientStop(stop.Color, stop.Offset));
}
}
brush = myBrush;
RotateTransform rotateTransform = new RotateTransform(colorObject.Angle, 0.5, 0.5);
myBrush.RelativeTransform = rotateTransform;
}
else if (colorObject.BrushType == BrushType.ImageBrush)
{
ImageBrush myBrush = new ImageBrush();
myBrush.ImageSource = new BitmapImage(new Uri(colorObject.Image, UriKind.Absolute));
brush = myBrush;
}
else if (colorObject.BrushType == BrushType.DrawingBrush)
{
DrawingBrush myBrush = new DrawingBrush();
GeometryDrawing backgroundSquare =
new GeometryDrawing(
Brushes.White,
null,
new RectangleGeometry(new Rect(0, 0, 100, 100)));
GeometryGroup aGeometryGroup = new GeometryGroup();
aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(0, 0, 50, 50)));
aGeometryGroup.Children.Add(new RectangleGeometry(new Rect(50, 50, 50, 50)));
LinearGradientBrush checkerBrush = new LinearGradientBrush();
checkerBrush.GradientStops.Add(new System.Windows.Media.GradientStop(Colors.Black, 0.0));
checkerBrush.GradientStops.Add(new System.Windows.Media.GradientStop(Colors.Gray, 1.0));
GeometryDrawing checkers = new GeometryDrawing(checkerBrush, null, aGeometryGroup);
DrawingGroup checkersDrawingGroup = new DrawingGroup();
checkersDrawingGroup.Children.Add(backgroundSquare);
checkersDrawingGroup.Children.Add(checkers);
myBrush.Drawing = checkersDrawingGroup;
myBrush.Viewport = new Rect(0, 0, 0.25, 0.25);
myBrush.TileMode = TileMode.Tile;
brush = myBrush;
}
if (brush != null)
{
brush.Opacity = colorObject.Opacity;
}
}
else if (value is ObservableCollection<GradientStop> gradientStop)
{
LinearGradientBrush myBrush = new LinearGradientBrush();
myBrush.StartPoint = new Point(0, 0.5);
myBrush.EndPoint = new Point(1, 0.5);
if (gradientStop != null)
{
foreach (var stop in gradientStop)
{
myBrush.GradientStops.Add(new System.Windows.Media.GradientStop(stop.Color, stop.Offset));
}
}
brush = myBrush;
}
return brush;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,32 @@
using AIStudio.Wpf.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ConectorOrientationConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string)
{
string str = value as string;
return -5 - (str.Length * 4);
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,47 @@
using AIStudio.Wpf.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ConectorValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values == null || values.Length < 1)
{
throw new NotImplementedException();
}
if (values[0] is double && values[1] is ValueTypePoint)
{
double connectorValue = (double)values[0];
ValueTypePoint valueTypePoint = (ValueTypePoint)values[1];
if (valueTypePoint == ValueTypePoint.Bool)
{
return (connectorValue == 0) ? "F" : "T";
}
else if (valueTypePoint == ValueTypePoint.Int)
{
return connectorValue.ToString("0");
}
else
{
return connectorValue.ToString("f3");
}
}
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ConnectionDataConverter : IMultiValueConverter
{
static ConnectionDataConverter()
{
Instance = new ConnectionDataConverter();
}
public static ConnectionDataConverter Instance
{
get;
private set;
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
List<PointInfoBase> points = (List<PointInfoBase>)values[0];
PathGeometry pathGeometry = new PathGeometry();
PathFigure figure = new PathFigure();
figure.StartPoint = points[0];
if (values[1]?.ToString() == DrawMode.RadiusConnectingLine.ToString())
{
for (var i = 0; i < points.Count - 1; i++)
{
int current = i, last = i - 1, next = i + 1, next2 = i + 2;
if (last == -1)
{
last = 0;
}
if (next == points.Count)
{
next = points.Count - 1;
}
if (next2 == points.Count)
{
next2 = points.Count - 1;
}
var bzs = SegmentHelper.GetBezierSegment(points[current], points[last], points[next], points[next2]);
figure.Segments.Add(bzs);
}
}
else
{
for (int i = 0; i < points.Count; i++)
{
LineSegment arc = new LineSegment(points[i], true);
figure.Segments.Add(arc);
}
}
pathGeometry.Figures.Add(figure);
return pathGeometry;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
[ValueConversion(typeof(List<Point>), typeof(PathSegmentCollection))]
public class ConnectionPathConverter : IValueConverter
{
static ConnectionPathConverter()
{
Instance = new ConnectionPathConverter();
}
public static ConnectionPathConverter Instance
{
get;
private set;
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
List<PointInfoBase> points = (List<PointInfoBase>)value;
PointCollection pointCollection = new PointCollection();
if (points != null)
{
foreach (var point in points)
{
pointCollection.Add(point);
}
}
return pointCollection;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,85 @@
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace AIStudio.Wpf.DiagramDesigner
{
public class DoubleToThickness : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
if (parameter != null)
{
switch (parameter.ToString())
{
case "Left":
return new Thickness(System.Convert.ToDouble(value), 0, 0, 0);
case "Top":
return new Thickness(0, System.Convert.ToDouble(value), 0, 0);
case "Right":
return new Thickness(0, 0, System.Convert.ToDouble(value), 0);
case "Buttom":
return new Thickness(0, 0, 0, System.Convert.ToDouble(value));
case "LeftTop":
return new Thickness(System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0, 0);
case "LeftButtom":
return new Thickness(System.Convert.ToDouble(value), 0, 0, System.Convert.ToDouble(value));
case "RightTop":
return new Thickness(0, System.Convert.ToDouble(value), System.Convert.ToDouble(value), 0);
case "RigthButtom":
return new Thickness(0, 0, System.Convert.ToDouble(value), System.Convert.ToDouble(value));
case "LeftRight":
return new Thickness(System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value), 0);
case "TopButtom":
return new Thickness(0, System.Convert.ToDouble(value), 0, System.Convert.ToDouble(value));
default:
return new Thickness(System.Convert.ToDouble(value));
}
}
return new Thickness(System.Convert.ToDouble(value));
}
return new Thickness(0);
}
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
if (parameter != null)
{
switch (parameter.ToString())
{
case "Left":
return ((Thickness)value).Left;
case "Top":
return ((Thickness)value).Top;
case "Right":
return ((Thickness)value).Right;
case "Buttom":
return ((Thickness)value).Bottom;
default:
return ((Thickness)value).Left;
}
}
return ((Thickness)value).Left;
}
return 0.0;
}
}
}

View File

@@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Data;
namespace AIStudio.Wpf.DiagramDesigner
{
public class EnumDescriptionConverter : IValueConverter
{
#region constructor
/// <summary>
/// Initializes a new instance of the <see cref="EnumDescriptionConverter"/> class.
/// </summary>
public EnumDescriptionConverter()
{
}
#endregion
#region IValueConverter
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
if (value is Enum)
{
return ((Enum)value).GetDescription();
}
else
{
return value.ToString();
}
}
else
{
return string.Empty;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
}

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 AIStudio.Wpf.DiagramDesigner
{
[ValueConversion(typeof(string), typeof(ImageSource))]
public class ImageUrlConverter : IValueConverter
{
static ImageUrlConverter()
{
Instance = new ImageUrlConverter();
}
public static ImageUrlConverter Instance
{
get;
private set;
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Uri imagePath = new Uri(value.ToString(), UriKind.RelativeOrAbsolute);
ImageSource source = new BitmapImage(imagePath);
return source;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
namespace AIStudio.Wpf.DiagramDesigner
{
public class InvertBoolConverter : MarkupExtension, IValueConverter
{
/// <summary>
/// Returns the value for the target property of this markup extension.
/// </summary>
/// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
/// <returns>Reference to the instance of this Int32IndexToNumberConverter.</returns>
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Windows.Data;
namespace AIStudio.Wpf.DiagramDesigner
{
public class LineDashConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is LineDashStyle arrowStyle)
{
return StrokeDashArray.Dash[(int)arrowStyle];
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,23 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace AIStudio.Wpf.DiagramDesigner
{
/// <summary>
/// 这是一个颠倒黑白的世界
/// </summary>
public sealed class TrueToFalseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var v = (bool)value;
return !v;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
public enum DiagramType
{
Normal,
FlowChart,
Logical,
SFC,
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
public enum LineDashStyle
{
None,
Dash1,
Dash2,
Dash3,
Dash4,
Dash5,
Dash6,
Dash7,
Dash8,
Dash9,
Dash10,
Dash11,
Dash12,
Dash13,
Dash14,
Dash15,
Dash16,
Dash17,
Dash18,
Dash19,
Dash20,
Dash21
}
}

View File

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

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
public enum LockFlag
{
[Description("无锁定")]
None,
[Description("锁定所有")]
All,
[Description("宽度(敬请期待)")]
Width,
[Description("高度(敬请期待)")]
Height,
[Description("纵横比(敬请期待)")]
Ratio,
[Description("水平位置(敬请期待)")]
Horizontal,
[Description("垂直位置(敬请期待)")]
Vertical,
[Description("旋转(敬请期待)")]
Rotate,
[Description("起点(敬请期待)")]
Start,
[Description("终点(敬请期待)")]
End,
[Description("取消组合(敬请期待)")]
UnGroup,
[Description("编辑文本(敬请期待)")]
Text,
[Description("保护选中(敬请期待)")]
IsSelected,
[Description("保护删除(敬请期待)")]
Delete,
[Description("阻止连接(敬请期待)")]
Link,
[Description("格式(敬请期待)")]
Format,
[Description("保护主题(敬请期待)")]
Theme,
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
public enum LogicalType
{
Input = -4,
Output = -3,
Constant = -2,
Time = -1,
None = 0,
ADD = 1,
SUB = 2,
MUL = 3,
DIV = 4,
AVE = 5,
MOD = 6,
AND = 7,
OR = 8,
XOR = 9,
NOT = 10,
SHL = 11,//左移
SHR = 12,//又移
ROL = 13,//循环左移
ROR = 14,//循环右移
SEL = 15,//选择
MAX = 16,
MIN = 17,
LIMIT = 18,//限幅
GT = 19,//大于
LT = 20,//小于
GE = 21,//大于等于
LE = 22,//小于等于
EQ = 23,//等于
NE = 24,//不等于
ABS = 25,
SQRT = 26,
LN = 27,
LOG = 28,
EXP = 29,
SIN = 30,
COS = 31,
TAN = 32,
ASIN = 33,
ACOS = 34,
ATAN = 35,
EXPT = 36,//幂
Bool2Double = 37,
Double2Bool = 38,
BoolsToDouble = 39,
DoubleToBools = 40,
}
}

View File

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

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
public enum PageSizeType
{
[Description("Letter,8.5英寸*11英寸")]//612*792
Letter,
[Description("Folio,8.5英寸*13英寸")]//612*936
Folio,
[Description("Folio,8.5英寸*14英寸")]//612*1008
Legal,
[Description("Folio,7.25英寸*10.5英寸")]//522*756
Executive,
[Description("Folio,5.5英寸*8.5英寸")]//396*612
Statement,
[Description("#10 Envelope,4.125英寸*9.5英寸")]//297*684
Envelope,
[Description("Monarch Envelope,3.875英寸*7.5英寸")]//279*540
MonarchEnvelope,
[Description("Tabloid,11英寸*17英寸")]//792*1224
Tabloid,
[Description("Letter Small,8 1/2英寸*11英寸")]//612*792
LetterSmall,
[Description("C Sheet,17英寸*22英寸")]//1224*1584
CSheet,
[Description("D Sheet,22英寸*34英寸")]//1584*2448
DSheet,
[Description("E Sheet,34英寸*44英寸")]//2448*3168
ESheet,
[Description("A3 sheet,297毫米*420毫米")]//842*1191
A3,
[Description("A4 sheet,210毫米*297毫米")]//595*842
A4,
[Description("A5 sheet,148毫米*210毫米")]//420*595
A5,
[Description("B4 sheet,250毫米*354毫米")]//709*1003
B4,
[Description("B5 sheet,182毫米*257毫米")]//516*729
B5,
[Description("DL Envelope,110毫米*220毫米")]//312*624
DLEnvelope,
[Description("C5 Envelope,162毫米*229毫米")]//459*649
C5Envelope,
[Description("Quarto,215毫米*275毫米")]//609*780
Quarto,
[Description("C6 Quarto,114毫米*162毫米")]//323*459
C6Quarto,
[Description("B5 Quarto,176毫米*250毫米")]//499*709
B5Quarto,
[Description("Italy Quarto,110毫米*230毫米")]//312*652
ItalyQuarto,
[Description("A4 small sheet,210毫米*297毫米")]//595*842
A4small,
[Description("German Std Fanfold,8.5英寸*12英寸")]//612*864
GermanStdFanfold,
[Description("German Lagal Fanfold,8英寸*13英寸")]//576*936
GermanLegalFanfold,
[Description("PRC 16K,146毫米*215毫米")]//414*609
PRC16K,
[Description("PRC 32K,97毫米*151毫米")]//275*428
PRC32K,
//[Description("Japanese Postcard")]//283*420
//JapanesePostcard,
//[Description("Double Japanese Postcard")]//420*566
//DoubleJapanesePostcard,
[Description("自定义")]
Custom,
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
public enum PageUnit
{
[Description("毫米(暂未实现)")]
mm,
[Description("厘米")]
cm,
[Description("米(暂未实现)")]
m,
[Description("千米(暂未实现)")]
km,
[Description("英寸")]
inch,
[Description("英尺和英寸(暂未实现)")]
ftin,
[Description("英尺(暂未实现)")]
foot,
[Description("码(暂未实现)")]
yard,
[Description("英里(暂未实现)")]
mile,
[Description("点(暂未实现)")]
tiny,
[Description("皮卡(暂未实现)")]
pickup,
[Description("迪多(暂未实现)")]
ditto,
[Description("西塞罗(暂未实现)")]
cicero,
[Description("像素(暂未实现)")]
pixel,
}
}

View File

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

View File

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

View File

@@ -0,0 +1,626 @@
using System;
using System.Windows.Media;
namespace AIStudio.Wpf.DiagramDesigner
{
/// <summary>
/// 类 名ColorHelper
/// 功 能提供从RGB到HSV/HSL色彩空间的相互转换
/// 日 期2015-02-08
/// 修 改2015-03-20
/// 作 者ls9512
/// </summary>
public static class ColorHelper
{
public static Color AdjustBrightness(Color c1, double factor)
{
double r = ((c1.R * factor) > 255) ? 255 : (c1.R * factor);
double g = ((c1.G * factor) > 255) ? 255 : (c1.G * factor);
double b = ((c1.B * factor) > 255) ? 255 : (c1.B * factor);
Color c = Color.FromArgb(c1.A, (byte)r, (byte)g, (byte)b);
return c;
}
/// <summary>
/// RGB转换HSV
/// </summary>
/// <param name="rgb"></param>
/// <returns></returns>
public static ColorHSV RgbToHsv(ColorRGB rgb)
{
float min, max, tmp, H, S, V;
float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
tmp = Math.Min(R, G);
min = Math.Min(tmp, B);
tmp = Math.Max(R, G);
max = Math.Max(tmp, B);
// H
H = 0;
if (max == min)
{
H = 0;
}
else if (max == R && G > B)
{
H = 60 * (G - B) * 1.0f / (max - min) + 0;
}
else if (max == R && G < B)
{
H = 60 * (G - B) * 1.0f / (max - min) + 360;
}
else if (max == G)
{
H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
}
else if (max == B)
{
H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
}
// S
if (max == 0)
{
S = 0;
}
else
{
S = (max - min) * 1.0f / max;
}
// V
V = max;
return new ColorHSV((int)H, (int)(S * 255), (int)(V * 255));
}
/// <summary>
/// HSV转换RGB
/// </summary>
/// <param name="hsv"></param>
/// <returns></returns>
public static ColorRGB HsvToRgb(ColorHSV hsv)
{
if (hsv.H == 360) hsv.H = 359; // 360为全黑原因不明
float R = 0f, G = 0f, B = 0f;
if (hsv.S == 0)
{
return new ColorRGB(hsv.V, hsv.V, hsv.V);
}
float S = hsv.S * 1.0f / 255, V = hsv.V * 1.0f / 255;
int H1 = (int)(hsv.H * 1.0f / 60), H = hsv.H;
float F = H * 1.0f / 60 - H1;
float P = V * (1.0f - S);
float Q = V * (1.0f - F * S);
float T = V * (1.0f - (1.0f - F) * S);
switch (H1)
{
case 0: R = V; G = T; B = P; break;
case 1: R = Q; G = V; B = P; break;
case 2: R = P; G = V; B = T; break;
case 3: R = P; G = Q; B = V; break;
case 4: R = T; G = P; B = V; break;
case 5: R = V; G = P; B = Q; break;
}
R = R * 255;
G = G * 255;
B = B * 255;
while (R > 255) R -= 255;
while (R < 0) R += 255;
while (G > 255) G -= 255;
while (G < 0) G += 255;
while (B > 255) B -= 255;
while (B < 0) B += 255;
return new ColorRGB((int)R, (int)G, (int)B);
}
/// <summary>
/// RGB转换HSL
/// </summary>
/// <param name="rgb"></param>
/// <returns></returns>
public static ColorHSL RgbToHsl(ColorRGB rgb)
{
float min, max, tmp, H, S, L;
float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
tmp = Math.Min(R, G);
min = Math.Min(tmp, B);
tmp = Math.Max(R, G);
max = Math.Max(tmp, B);
// H
H = 0;
if (max == min)
{
H = 0; // 此时H应为未定义通常写为0
}
else if (max == R && G > B)
{
H = 60 * (G - B) * 1.0f / (max - min) + 0;
}
else if (max == R && G < B)
{
H = 60 * (G - B) * 1.0f / (max - min) + 360;
}
else if (max == G)
{
H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
}
else if (max == B)
{
H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
}
// L
L = 0.5f * (max + min);
// S
S = 0;
if (L == 0 || max == min)
{
S = 0;
}
else if (0 < L && L < 0.5)
{
S = (max - min) / (L * 2);
}
else if (L > 0.5)
{
S = (max - min) / (2 - 2 * L);
}
return new ColorHSL((int)H, (int)(S * 255), (int)(L * 255));
}
/// <summary>
/// HSL转换RGB
/// </summary>
/// <param name="hsl"></param>
/// <returns></returns>
public static ColorRGB HslToRgb(ColorHSL hsl)
{
float R = 0f, G = 0f, B = 0f;
float S = hsl.S * 1.0f / 255, L = hsl.L * 1.0f / 255;
float temp1, temp2, temp3;
if (S == 0f) // 灰色
{
R = L;
G = L;
B = L;
}
else
{
if (L < 0.5f)
{
temp2 = L * (1.0f + S);
}
else
{
temp2 = L + S - L * S;
}
temp1 = 2.0f * L - temp2;
float H = hsl.H * 1.0f / 360;
// R
temp3 = H + 1.0f / 3.0f;
if (temp3 < 0) temp3 += 1.0f;
if (temp3 > 1) temp3 -= 1.0f;
R = temp3;
// G
temp3 = H;
if (temp3 < 0) temp3 += 1.0f;
if (temp3 > 1) temp3 -= 1.0f;
G = temp3;
// B
temp3 = H - 1.0f / 3.0f;
if (temp3 < 0) temp3 += 1.0f;
if (temp3 > 1) temp3 -= 1.0f;
B = temp3;
}
R = R * 255;
G = G * 255;
B = B * 255;
return new ColorRGB((int)R, (int)G, (int)B);
}
/// <summary>
/// RGB转换HSV
/// </summary>
/// <param name="rgb"></param>
/// <returns></returns>
public static ColorHSV ColorToHsv(Color rgb)
{
float min, max, tmp, H, S, V;
float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
tmp = Math.Min(R, G);
min = Math.Min(tmp, B);
tmp = Math.Max(R, G);
max = Math.Max(tmp, B);
// H
H = 0;
if (max == min)
{
H = 0;
}
else if (max == R && G > B)
{
H = 60 * (G - B) * 1.0f / (max - min) + 0;
}
else if (max == R && G < B)
{
H = 60 * (G - B) * 1.0f / (max - min) + 360;
}
else if (max == G)
{
H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
}
else if (max == B)
{
H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
}
// S
if (max == 0)
{
S = 0;
}
else
{
S = (max - min) * 1.0f / max;
}
// V
V = max;
return new ColorHSV((int)H, (int)(S * 255), (int)(V * 255));
}
/// <summary>
/// HSV转换RGB
/// </summary>
/// <param name="hsv"></param>
/// <returns></returns>
public static Color HsvToColor(ColorHSV hsv)
{
if (hsv.H == 360) hsv.H = 359; // 360为全黑原因不明
float R = 0f, G = 0f, B = 0f;
if (hsv.S == 0)
{
return Color.FromArgb(0xff, (byte)hsv.V, (byte)hsv.V, (byte)hsv.V);
}
float S = hsv.S * 1.0f / 255, V = hsv.V * 1.0f / 255;
int H1 = (int)(hsv.H * 1.0f / 60), H = hsv.H;
float F = H * 1.0f / 60 - H1;
float P = V * (1.0f - S);
float Q = V * (1.0f - F * S);
float T = V * (1.0f - (1.0f - F) * S);
switch (H1)
{
case 0: R = V; G = T; B = P; break;
case 1: R = Q; G = V; B = P; break;
case 2: R = P; G = V; B = T; break;
case 3: R = P; G = Q; B = V; break;
case 4: R = T; G = P; B = V; break;
case 5: R = V; G = P; B = Q; break;
}
R = R * 255;
G = G * 255;
B = B * 255;
while (R > 255) R -= 255;
while (R < 0) R += 255;
while (G > 255) G -= 255;
while (G < 0) G += 255;
while (B > 255) B -= 255;
while (B < 0) B += 255;
return Color.FromArgb(0xff, (byte)R, (byte)G, (byte)B);
}
/// <summary>
/// RGB转换HSL
/// </summary>
/// <param name="rgb"></param>
/// <returns></returns>
public static ColorHSL ColorToHsl(Color rgb)
{
float min, max, tmp, H, S, L;
float R = rgb.R * 1.0f / 255, G = rgb.G * 1.0f / 255, B = rgb.B * 1.0f / 255;
tmp = Math.Min(R, G);
min = Math.Min(tmp, B);
tmp = Math.Max(R, G);
max = Math.Max(tmp, B);
// H
H = 0;
if (max == min)
{
H = 0; // 此时H应为未定义通常写为0
}
else if (max == R && G > B)
{
H = 60 * (G - B) * 1.0f / (max - min) + 0;
}
else if (max == R && G < B)
{
H = 60 * (G - B) * 1.0f / (max - min) + 360;
}
else if (max == G)
{
H = H = 60 * (B - R) * 1.0f / (max - min) + 120;
}
else if (max == B)
{
H = H = 60 * (R - G) * 1.0f / (max - min) + 240;
}
// L
L = 0.5f * (max + min);
// S
S = 0;
if (L == 0 || max == min)
{
S = 0;
}
else if (0 < L && L < 0.5)
{
S = (max - min) / (L * 2);
}
else if (L > 0.5)
{
S = (max - min) / (2 - 2 * L);
}
return new ColorHSL((int)H, (int)(S * 255), (int)(L * 255));
}
/// <summary>
/// HSL转换RGB
/// </summary>
/// <param name="hsl"></param>
/// <returns></returns>
public static Color HslToColor(ColorHSL hsl)
{
float R = 0f, G = 0f, B = 0f;
float S = hsl.S * 1.0f / 255, L = hsl.L * 1.0f / 255;
float temp1, temp2, temp3;
if (S == 0f) // 灰色
{
R = L;
G = L;
B = L;
}
else
{
if (L < 0.5f)
{
temp2 = L * (1.0f + S);
}
else
{
temp2 = L + S - L * S;
}
temp1 = 2.0f * L - temp2;
float H = hsl.H * 1.0f / 360;
// R
temp3 = H + 1.0f / 3.0f;
if (temp3 < 0) temp3 += 1.0f;
if (temp3 > 1) temp3 -= 1.0f;
R = temp3;
// G
temp3 = H;
if (temp3 < 0) temp3 += 1.0f;
if (temp3 > 1) temp3 -= 1.0f;
G = temp3;
// B
temp3 = H - 1.0f / 3.0f;
if (temp3 < 0) temp3 += 1.0f;
if (temp3 > 1) temp3 -= 1.0f;
B = temp3;
}
R = R * 255;
G = G * 255;
B = B * 255;
return Color.FromArgb(0xff, (byte)R, (byte)G, (byte)B);
}
}
#region RGB / HSV / HSL
/// <summary>
/// 类 名ColorHSL
/// 功 能H 色相 \ S 饱和度(纯度) \ L 亮度 颜色模型
/// 日 期2015-02-08
/// 修 改2015-03-20
/// 作 者ls9512
/// </summary>
public class ColorHSL
{
public ColorHSL(int h, int s, int l)
{
this._h = h;
this._s = s;
this._l = l;
}
private int _h;
private int _s;
private int _l;
/// <summary>
/// 色相
/// </summary>
public int H
{
get { return this._h; }
set
{
this._h = value;
this._h = this._h > 360 ? 360 : this._h;
this._h = this._h < 0 ? 0 : this._h;
}
}
/// <summary>
/// 饱和度(纯度)
/// </summary>
public int S
{
get { return this._s; }
set
{
this._s = value;
this._s = this._s > 255 ? 255 : this._s;
this._s = this._s < 0 ? 0 : this._s;
}
}
/// <summary>
/// 饱和度
/// </summary>
public int L
{
get { return this._l; }
set
{
this._l = value;
this._l = this._l > 255 ? 255 : this._l;
this._l = this._l < 0 ? 0 : this._l;
}
}
}
/// <summary>
/// 类 名ColorHSV
/// 功 能H 色相 \ S 饱和度(纯度) \ V 明度 颜色模型
/// 日 期2015-01-22
/// 修 改2015-03-20
/// 作 者ls9512
/// </summary>
public class ColorHSV
{
/// <summary>
/// 构造方法
/// </summary>
/// <param name="h"></param>
/// <param name="s"></param>
/// <param name="v"></param>
public ColorHSV(int h, int s, int v)
{
this._h = h;
this._s = s;
this._v = v;
}
private int _h;
private int _s;
private int _v;
/// <summary>
/// 色相
/// </summary>
public int H
{
get { return this._h; }
set
{
this._h = value;
this._h = this._h > 360 ? 360 : this._h;
this._h = this._h < 0 ? 0 : this._h;
}
}
/// <summary>
/// 饱和度(纯度)
/// </summary>
public int S
{
get { return this._s; }
set
{
this._s = value;
this._s = this._s > 255 ? 255 : this._s;
this._s = this._s < 0 ? 0 : this._s;
}
}
/// <summary>
/// 明度
/// </summary>
public int V
{
get { return this._v; }
set
{
this._v = value;
this._v = this._v > 255 ? 255 : this._v;
this._v = this._v < 0 ? 0 : this._v;
}
}
}
/// <summary>
/// 类 名ColorRGB
/// 功 能R 红色 \ G 绿色 \ B 蓝色 颜色模型
/// 所有颜色模型的基类RGB是用于输出到屏幕的颜色模式所以所有模型都将转换成RGB输出
/// 日 期2015-01-22
/// 修 改2015-03-20
/// 作 者ls9512
/// </summary>
public class ColorRGB
{
/// <summary>
/// 构造方法
/// </summary>
/// <param name="r"></param>
/// <param name="g"></param>
/// <param name="b"></param>
public ColorRGB(int r, int g, int b)
{
this._r = r;
this._g = g;
this._b = b;
}
private int _r;
private int _g;
private int _b;
/// <summary>
/// 红色
/// </summary>
public int R
{
get { return this._r; }
set
{
this._r = value;
this._r = this._r > 255 ? 255 : this._r;
this._r = this._r < 0 ? 0 : this._r;
}
}
/// <summary>
/// 绿色
/// </summary>
public int G
{
get { return this._g; }
set
{
this._g = value;
this._g = this._g > 255 ? 255 : this._g;
this._g = this._g < 0 ? 0 : this._g;
}
}
/// <summary>
/// 蓝色
/// </summary>
public int B
{
get { return this._b; }
set
{
this._b = value;
this._b = this._b > 255 ? 255 : this._b;
this._b = this._b < 0 ? 0 : this._b;
}
}
/// <summary>
/// 获取实际颜色
/// </summary>
/// <returns></returns>
public Color GetColor()
{
return Color.FromArgb(0xff, (byte)this._r, (byte)this._g, (byte)this._b);
}
}
#endregion
}

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
/// <summary>
/// 获取当前光标处颜色win8下wpf测试成功
/// </summary>
public class ColorPickerManager
{
/// <summary>
///
/// </summary>
/// <param name="x">鼠标相对于显示器的坐标X</param>
/// <param name="y">鼠标相对于显示器的坐标Y</param>
/// <returns></returns>
//public static System.Drawing.Color GetColor(int x, int y)
//{
// IntPtr hdc = GetDC(IntPtr.Zero);
// uint pixel = GetPixel(hdc, x, y);
// ReleaseDC(IntPtr.Zero, hdc);
// System.Drawing.Color color = System.Drawing.Color.FromArgb((int)(pixel & 0x000000FF), (int)(pixel & 0x0000FF00) >> 8, (int)(pixel & 0x00FF0000) >> 16);
// return color;
//}
/// <summary>
///
/// </summary>
/// <param name="x">鼠标相对于显示器的坐标X</param>
/// <param name="y">鼠标相对于显示器的坐标Y</param>
/// <returns></returns>
public static System.Windows.Media.Color GetColor(int x, int y)
{
IntPtr hdc = GetDC(IntPtr.Zero);
uint pixel = GetPixel(hdc, x, y);
ReleaseDC(IntPtr.Zero, hdc);
System.Windows.Media.Color color = System.Windows.Media.Color.FromRgb((byte)(pixel & 0x000000FF), (byte)((pixel & 0x0000FF00) >> 8), (byte)((pixel & 0x00FF0000) >> 16));
return color;
}
[DllImport("gdi32.dll")]
private static extern bool BitBlt(
IntPtr hdcDest, // 目标设备的句柄
int nXDest, // 目标对象的左上角的X坐标
int nYDest, // 目标对象的左上角的X坐标
int nWidth, // 目标对象的矩形的宽度
int nHeight, // 目标对象的矩形的长度
IntPtr hdcSrc, // 源设备的句柄
int nXSrc, // 源对象的左上角的X坐标
int nYSrc, // 源对象的左上角的X坐标
int dwRop // 光栅的操作值
);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateDC(
string lpszDriver, // 驱动名称
string lpszDevice, // 设备名称
string lpszOutput, // 无用,可以设定位"NULL"
IntPtr lpInitData // 任意的打印机数据
);
/// <summary>
/// 获取指定窗口的设备场景
/// </summary>
/// <param name="hwnd">将获取其设备场景的窗口的句柄。若为0则要获取整个屏幕的DC</param>
/// <returns>指定窗口的设备场景句柄出错则为0</returns>
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);
/// <summary>
/// 释放由调用GetDC函数获取的指定设备场景
/// </summary>
/// <param name="hwnd">要释放的设备场景相关的窗口句柄</param>
/// <param name="hdc">要释放的设备场景句柄</param>
/// <returns>执行成功为1否则为0</returns>
[DllImport("user32.dll")]
private static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
/// <summary>
/// 在指定的设备场景中取得一个像素的RGB值
/// </summary>
/// <param name="hdc">一个设备场景的句柄</param>
/// <param name="nXPos">逻辑坐标中要检查的横坐标</param>
/// <param name="nYPos">逻辑坐标中要检查的纵坐标</param>
/// <returns>指定点的颜色</returns>
[DllImport("gdi32.dll")]
private static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace AIStudio.Wpf.DiagramDesigner
{
public struct ConnectorInfo
{
public double DesignerItemLeft { get; set; }
public double DesignerItemTop { get; set; }
public Size DesignerItemSize { get; set; }
public Point Position { get; set; }
public ConnectorOrientation Orientation { get; set; }
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public static class ControlExtession
{
#region TreeView操作扩展方法
//code:http://www.codeproject.com/Articles/36193/WPF-TreeView-tools
/// <summary>
/// Returns the TreeViewItem of a data bound object.
/// </summary>
/// <param name="treeView">TreeView</param>
/// <param name="obj">Data bound object</param>
/// <returns>The TreeViewItem of the data bound object or null.</returns>
public static TreeViewItem GetItemFromObject(this TreeView treeView, object obj)
{
try
{
DependencyObject dObject = GetContainerFormObject(treeView, obj);
TreeViewItem tvi = dObject as TreeViewItem;
while (tvi == null)
{
dObject = VisualTreeHelper.GetParent(dObject);
tvi = dObject as TreeViewItem;
}
return tvi;
}
catch
{
}
return null;
}
private static DependencyObject GetContainerFormObject(ItemsControl item, object obj)
{
if (item == null)
return null;
DependencyObject dObject = null;
dObject = item.ItemContainerGenerator.ContainerFromItem(obj);
if (dObject != null)
return dObject;
var query = from childItem in item.Items.Cast<object>()
let childControl = item.ItemContainerGenerator.ContainerFromItem(childItem) as ItemsControl
select GetContainerFormObject(childControl, obj);
return query.FirstOrDefault(i => i != null);
}
/// <summary>
/// Selects a data bound object of a TreeView.
/// </summary>
/// <param name="treeView">TreeView</param>
/// <param name="obj">Data bound object</param>
public static void SelectObject(this TreeView treeView, object obj)
{
treeView.SelectObject(obj, true);
}
/// <summary>
/// Selects or deselects a data bound object of a TreeView.
/// </summary>
/// <param name="treeView">TreeView</param>
/// <param name="obj">Data bound object</param>
/// <param name="selected">select or deselect</param>
public static void SelectObject(this TreeView treeView, object obj, bool selected)
{
var tvi = treeView.GetItemFromObject(obj);
if (tvi != null)
{
tvi.IsSelected = selected;
}
}
/// <summary>
/// Returns if a data bound object of a TreeView is selected.
/// </summary>
/// <param name="treeView">TreeView</param>
/// <param name="obj">Data bound object</param>
/// <returns>Returns true if the object is selected, and false if it is not selected or obj is not in the tree.</returns>
public static bool IsObjectSelected(this TreeView treeView, object obj)
{
var tvi = treeView.GetItemFromObject(obj);
if (tvi != null)
{
return tvi.IsSelected;
}
return false;
}
/// <summary>
/// Returns if a data bound object of a TreeView is focused.
/// </summary>
/// <param name="treeView">TreeView</param>
/// <param name="obj">Data bound object</param>
/// <returns>Returns true if the object is focused, and false if it is not focused or obj is not in the tree.</returns>
public static bool IsObjectFocused(this TreeView treeView, object obj)
{
var tvi = treeView.GetItemFromObject(obj);
if (tvi != null)
{
return tvi.IsFocused;
}
return false;
}
/// <summary>
/// Expands a data bound object of a TreeView.
/// </summary>
/// <param name="treeView">TreeView</param>
/// <param name="obj">Data bound object</param>
public static void ExpandObject(this TreeView treeView, object obj)
{
treeView.ExpandObject(obj, true);
}
/// <summary>
/// Expands or collapses a data bound object of a TreeView.
/// </summary>
/// <param name="treeView">TreeView</param>
/// <param name="obj">Data bound object</param>
/// <param name="expanded">expand or collapse</param>
public static void ExpandObject(this TreeView treeView, object obj, bool expanded)
{
var tvi = treeView.GetItemFromObject(obj);
if (tvi != null)
{
tvi.IsExpanded = expanded;
if (expanded)
{
// update layout, so that following calls to f.e. SelectObject on child nodes will
// find theire TreeViewNodes
treeView.UpdateLayout();
}
}
}
/// <summary>
/// Returns if a douta bound object of a TreeView is expanded.
/// </summary>
/// <param name="treeView">TreeView</param>
/// <param name="obj">Data bound object</param>
/// <returns>Returns true if the object is expanded, and false if it is collapsed or obj is not in the tree.</returns>
public static bool IsObjectExpanded(this TreeView treeView, object obj)
{
var tvi = treeView.GetItemFromObject(obj);
if (tvi != null)
{
return tvi.IsExpanded;
}
return false;
}
/// <summary>
/// Retuns the parent TreeViewItem.
/// </summary>
/// <param name="item">TreeViewItem</param>
/// <returns>Parent TreeViewItem</returns>
public static TreeViewItem GetParentItem(this TreeViewItem item)
{
var dObject = VisualTreeHelper.GetParent(item);
TreeViewItem tvi = dObject as TreeViewItem;
while (tvi == null)
{
dObject = VisualTreeHelper.GetParent(dObject);
tvi = dObject as TreeViewItem;
}
return tvi;
}
#endregion
#region FindParent/FindChildren
/// <summary>
/// Finds a parent of a given item on the visual tree.
/// </summary>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="child">A direct or indirect child of the
/// queried item.</param>
/// <returns>The first parent item that matches the submitted
/// type parameter. If not matching item can be found, a null
/// reference is being returned.</returns>
public static T TryFindParent<T>(this DependencyObject child)
where T : DependencyObject
{
//get parent item
DependencyObject parentObject = GetParentObject(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
return parent ?? TryFindParent<T>(parentObject);
}
//public static T FindParent<T>(DependencyObject child) where T : DependencyObject
//{
// //get parent item
// var parentObject = VisualTreeHelper.GetParent(child);
// //we've reached the end of the tree
// if (parentObject == null) return null;
// //check if the parent matches the type we're looking for
// var parent = parentObject as T;
// return parent ?? FindParent<T>(parentObject);
//}
/// <summary>
/// Finds a Child of a given item in the visual tree.
/// </summary>
/// <param name="parent">A direct parent of the queried item.</param>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="childName">x:Name or Name of child. </param>
/// <returns>The first parent item that matches the submitted type parameter.
/// If not matching item can be found,
/// a null parent is being returned.</returns>
public static T FindChild<T>(this DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
/// <summary>
/// This method is an alternative to WPF's
/// <see cref="VisualTreeHelper.GetParent"/> method, which also
/// supports content elements. Keep in mind that for content element,
/// this method falls back to the logical tree of the element!
/// </summary>
/// <param name="child">The item to be processed.</param>
/// <returns>The submitted item's parent, if available. Otherwise
/// null.</returns>
public static DependencyObject GetParentObject(this DependencyObject child)
{
if (child == null) return null;
//handle content elements separately
var contentElement = child as ContentElement;
if (contentElement != null)
{
DependencyObject parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
var fce = contentElement as FrameworkContentElement;
return fce != null ? fce.Parent : null;
}
//also try searching for parent in framework elements (such as DockPanel, etc)
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null)
{
DependencyObject parent = frameworkElement.Parent;
if (parent != null) return parent;
}
//if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
return VisualTreeHelper.GetParent(child);
}
/// <summary>
/// Analyzes both visual and logical tree in order to find all elements of a given
/// type that are descendants of the <paramref name="source"/> item.
/// </summary>
/// <typeparam name="T">The type of the queried items.</typeparam>
/// <param name="source">The root element that marks the source of the search. If the
/// source is already of the requested type, it will not be included in the result.</param>
/// <param name="forceUsingTheVisualTreeHelper">Sometimes it's better to search in the VisualTree (e.g. in tests)</param>
/// <returns>All descendants of <paramref name="source"/> that match the requested type.</returns>
public static IEnumerable<T> FindChildren<T>(this DependencyObject source, bool forceUsingTheVisualTreeHelper = false) where T : DependencyObject
{
if (source != null)
{
var childs = GetChildObjects(source, forceUsingTheVisualTreeHelper);
foreach (DependencyObject child in childs)
{
//analyze if children match the requested type
if (child != null && child is T)
{
yield return (T)child;
}
//recurse tree
foreach (T descendant in FindChildren<T>(child))
{
yield return descendant;
}
}
}
}
/// <summary>
/// This method is an alternative to WPF's
/// <see cref="VisualTreeHelper.GetChild"/> method, which also
/// supports content elements. Keep in mind that for content elements,
/// this method falls back to the logical tree of the element.
/// </summary>
/// <param name="parent">The item to be processed.</param>
/// <param name="forceUsingTheVisualTreeHelper">Sometimes it's better to search in the VisualTree (e.g. in tests)</param>
/// <returns>The submitted item's child elements, if available.</returns>
public static IEnumerable<DependencyObject> GetChildObjects(this DependencyObject parent, bool forceUsingTheVisualTreeHelper = false)
{
if (parent == null) yield break;
if (!forceUsingTheVisualTreeHelper && (parent is ContentElement || parent is FrameworkElement))
{
//use the logical tree for content / framework elements
foreach (object obj in LogicalTreeHelper.GetChildren(parent))
{
var depObj = obj as DependencyObject;
if (depObj != null) yield return (DependencyObject)obj;
}
}
else
{
//use the visual tree per default
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
yield return VisualTreeHelper.GetChild(parent, i);
}
}
}
/// <summary>
/// Tries to locate a given item within the visual tree,
/// starting with the dependency object at a given position.
/// </summary>
/// <typeparam name="T">The type of the element to be found
/// on the visual tree of the element at the given location.</typeparam>
/// <param name="reference">The main element which is used to perform
/// hit testing.</param>
/// <param name="point">The position to be evaluated on the origin.</param>
public static T TryFindFromPoint<T>(UIElement reference, Point point)
where T : DependencyObject
{
var element = reference.InputHitTest(point) as DependencyObject;
if (element == null)
return null;
if (element is T)
return (T)element;
return TryFindParent<T>(element);
//DependencyObject hitObject = reference.InputHitTest(point) as DependencyObject;
//while (hitObject != null &&
// hitObject.GetType() != typeof(DesignerCanvas))
//{
// if (hitObject is T)
// {
// return (T)hitObject;
// }
// hitObject = VisualTreeHelper.GetParent(hitObject);
//}
//return null;
}
#endregion
}
}

View File

@@ -0,0 +1,187 @@
using Microsoft.Xaml.Behaviors;
using System;
using System.Windows;
using System.Windows.Input;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ControlMouseDoubleClickCommandBehavior : Behavior<FrameworkElement>
{
#region Overrides
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
EnableDisableElement();
}
protected override void OnDetaching()
{
AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
}
#endregion
#region Private Methods
private void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//Get the ItemsControl and then get the item, and check there
//is an actual item, as if we are using a ListView we may have clicked the
//headers which are not items
//ItemsControl listView = sender as ItemsControl;
//DependencyObject originalSender = e.OriginalSource as DependencyObject;
//if (listView == null || originalSender == null) return;
//DependencyObject container =
// ItemsControl.ContainerFromElement
// (sender as ItemsControl, e.OriginalSource as DependencyObject);
//if (container == null ||
// container == DependencyProperty.UnsetValue) return;
//// found a container, now find the item.
//object activatedItem =
// listView.ItemContainerGenerator.ItemFromContainer(container);
//if (activatedItem != null)
//{
// Invoke(activatedItem, e);
//}
FrameworkElement control = sender as FrameworkElement;
DependencyObject originalSender = e.OriginalSource as DependencyObject;
if (control == null || originalSender == null) return;
if (e.ClickCount >= 2)
{
Invoke(control, e);
}
}
private static void OnCommandChanged(ControlMouseDoubleClickCommandBehavior thisBehaviour,
DependencyPropertyChangedEventArgs e)
{
if (thisBehaviour == null)
{
return;
}
if (e.OldValue != null)
{
((ICommand)e.OldValue).CanExecuteChanged -= thisBehaviour.OnCommandCanExecuteChanged;
}
ICommand command = (ICommand)e.NewValue;
if (command != null)
{
command.CanExecuteChanged += thisBehaviour.OnCommandCanExecuteChanged;
}
thisBehaviour.EnableDisableElement();
}
private bool IsAssociatedElementDisabled()
{
return AssociatedObject != null && !AssociatedObject.IsEnabled;
}
private void EnableDisableElement()
{
if (AssociatedObject == null || Command == null)
{
return;
}
AssociatedObject.IsEnabled = Command.CanExecute(this.CommandParameter);
}
private void OnCommandCanExecuteChanged(object sender, EventArgs e)
{
EnableDisableElement();
}
#endregion
#region Protected Methods
/// <param name="parameter">The EventArgs of the fired event.</param>
protected void Invoke(object clickedItem, MouseButtonEventArgs parameter)
{
if (IsAssociatedElementDisabled())
{
return;
}
ICommand command = Command;
if (command != null && command.CanExecute(CommandParameter))
{
command.Execute(new EventToCommandArgs(clickedItem, command,
CommandParameter, (EventArgs)parameter));
}
}
#endregion
#region DPs
#region CommandParameter
/// <summary>
/// Identifies the <see cref="CommandParameter" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
"CommandParameter", typeof(object), typeof(ControlMouseDoubleClickCommandBehavior),
new PropertyMetadata(null,
(s, e) =>
{
ControlMouseDoubleClickCommandBehavior sender = s as ControlMouseDoubleClickCommandBehavior;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This is a DependencyProperty.
/// </summary>
public object CommandParameter
{
get { return (Object)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
#endregion
#region Command
/// <summary
/// >
/// Identifies the <see cref="Command" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command", typeof(ICommand), typeof(ControlMouseDoubleClickCommandBehavior),
new PropertyMetadata(null,
(s, e) => OnCommandChanged(s as ControlMouseDoubleClickCommandBehavior, e)));
/// <summary>
/// Gets or sets the ICommand that this trigger is bound to. This
/// is a DependencyProperty.
/// </summary>
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
#endregion
#endregion
}
}

View File

@@ -0,0 +1,184 @@
using Microsoft.Xaml.Behaviors;
using System;
using System.Windows;
using System.Windows.Input;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ControlMouseLeftButtonDownCommandBehavior : Behavior<FrameworkElement>
{
#region Overrides
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;
EnableDisableElement();
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObject_PreviewMouseLeftButtonDown;
}
#endregion
#region Private Methods
private void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//Get the ItemsControl and then get the item, and check there
//is an actual item, as if we are using a ListView we may have clicked the
//headers which are not items
//ItemsControl listView = sender as ItemsControl;
//DependencyObject originalSender = e.OriginalSource as DependencyObject;
//if (listView == null || originalSender == null) return;
//DependencyObject container =
// ItemsControl.ContainerFromElement
// (sender as ItemsControl, e.OriginalSource as DependencyObject);
//if (container == null ||
// container == DependencyProperty.UnsetValue) return;
//// found a container, now find the item.
//object activatedItem =
// listView.ItemContainerGenerator.ItemFromContainer(container);
//if (activatedItem != null)
//{
// Invoke(activatedItem, e);
//}
FrameworkElement control = sender as FrameworkElement;
DependencyObject originalSender = e.OriginalSource as DependencyObject;
if (control == null || originalSender == null) return;
Invoke(control, e);
}
private static void OnCommandChanged(ControlMouseLeftButtonDownCommandBehavior thisBehaviour,
DependencyPropertyChangedEventArgs e)
{
if (thisBehaviour == null)
{
return;
}
if (e.OldValue != null)
{
((ICommand)e.OldValue).CanExecuteChanged -= thisBehaviour.OnCommandCanExecuteChanged;
}
ICommand command = (ICommand)e.NewValue;
if (command != null)
{
command.CanExecuteChanged += thisBehaviour.OnCommandCanExecuteChanged;
}
thisBehaviour.EnableDisableElement();
}
private bool IsAssociatedElementDisabled()
{
return AssociatedObject != null && !AssociatedObject.IsEnabled;
}
private void EnableDisableElement()
{
if (AssociatedObject == null || Command == null)
{
return;
}
AssociatedObject.IsEnabled = Command.CanExecute(this.CommandParameter);
}
private void OnCommandCanExecuteChanged(object sender, EventArgs e)
{
EnableDisableElement();
}
#endregion
#region Protected Methods
/// <param name="parameter">The EventArgs of the fired event.</param>
protected void Invoke(object clickedItem, MouseButtonEventArgs parameter)
{
if (IsAssociatedElementDisabled())
{
return;
}
ICommand command = Command;
if (command != null && command.CanExecute(CommandParameter))
{
command.Execute(new EventToCommandArgs(clickedItem, command,
CommandParameter, (EventArgs)parameter));
}
}
#endregion
#region DPs
#region CommandParameter
/// <summary>
/// Identifies the <see cref="CommandParameter" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
"CommandParameter", typeof(object), typeof(ControlMouseLeftButtonDownCommandBehavior),
new PropertyMetadata(null,
(s, e) =>
{
ControlMouseLeftButtonDownCommandBehavior sender = s as ControlMouseLeftButtonDownCommandBehavior;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This is a DependencyProperty.
/// </summary>
public object CommandParameter
{
get { return (Object)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
#endregion
#region Command
/// <summary
/// >
/// Identifies the <see cref="Command" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command", typeof(ICommand), typeof(ControlMouseLeftButtonDownCommandBehavior),
new PropertyMetadata(null,
(s, e) => OnCommandChanged(s as ControlMouseLeftButtonDownCommandBehavior, e)));
/// <summary>
/// Gets or sets the ICommand that this trigger is bound to. This
/// is a DependencyProperty.
/// </summary>
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
#endregion
#endregion
}
}

View File

@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml.Serialization;
namespace AIStudio.Wpf.DiagramDesigner
{
public class CopyHelper
{
public static T DeepCopyByReflect<T>(T obj)
{
//如果是字符串或值类型则直接返回
if (obj == null || obj is string || obj.GetType().IsValueType) return obj;
object retval = Activator.CreateInstance(obj.GetType());
FieldInfo[] fields = obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
foreach (FieldInfo field in fields)
{
try { field.SetValue(retval, DeepCopyByReflect(field.GetValue(obj))); }
catch { }
}
return (T)retval;
}
public static TChild AutoCopy<TParent, TChild>(TParent parent) where TChild : TParent, new()
{
TChild child = new TChild();
var ParentType = typeof(TParent);
var Properties = ParentType.GetProperties();
foreach (var Propertie in Properties)
{
//循环遍历属性
if (Propertie.CanRead && Propertie.CanWrite)
{
//进行属性拷贝
Propertie.SetValue(child, Propertie.GetValue(parent, null), null);
}
}
return child;
}
public static T AutoCopy<T>(T source) where T : new()
{
//如果是字符串或值类型则直接返回
if (source == null || source is string || source.GetType().IsValueType) return source;
T target = new T();
var Properties = typeof(T).GetProperties();
foreach (var Propertie in Properties)
{
//循环遍历属性
if (Propertie.CanRead && Propertie.CanWrite)
{
//进行属性拷贝
Propertie.SetValue(target, Propertie.GetValue(source, null), null);
}
}
return target;
}
public static T DeepCopy<T>(T obj)
{
//如果是字符串或值类型则直接返回
if (obj == null || obj is string || obj.GetType().IsValueType) return obj;
object retval;
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer xml = new XmlSerializer(typeof(T));
xml.Serialize(ms, obj);
ms.Seek(0, SeekOrigin.Begin);
retval = xml.Deserialize(ms);
ms.Close();
}
return (T)retval;
}
/// <summary>
/// 反射实现两个类的对象之间相同属性的值的复制
/// 适用于初始化新实体
/// </summary>
/// <typeparam name="D">返回的实体</typeparam>
/// <typeparam name="S">数据源实体</typeparam>
/// <param name="s">数据源实体</param>
/// <returns>返回的新实体</returns>
public static D Mapper<D, S>(S s)
{
D d = Activator.CreateInstance<D>(); //构造新实例
try
{
var Types = s.GetType();//获得类型
var Typed = typeof(D);
foreach (PropertyInfo sp in Types.GetProperties().Where(p => p.CanRead))//获得类型的属性字段
{
foreach (PropertyInfo dp in Typed.GetProperties().Where(p => p.CanWrite))
{
if (dp.Name == sp.Name && dp.PropertyType == sp.PropertyType)//判断属性名是否相同
{
dp.SetValue(d, sp.GetValue(s, null), null);//获得s对象属性的值复制给d对象的属性
}
}
}
}
catch (Exception ex)
{
throw ex;
}
return d;
}
public static void CopyPropertyValue(object s, object d, string propertyName = null)
{
try
{
var Types = s.GetType();//获得类型
var Typed = d.GetType();
var sps = Types.GetProperties().Where(p => p.CanRead && (string.IsNullOrEmpty(propertyName) || p.Name == propertyName));//获得类型的属性字段
var dps = Typed.GetProperties().Where(p => p.CanWrite && (string.IsNullOrEmpty(propertyName) || p.Name == propertyName));
foreach (PropertyInfo sp in sps)//获得类型的属性字段
{
foreach (PropertyInfo dp in dps)
{
if (dp.Name == sp.Name && dp.PropertyType == sp.PropertyType)//判断属性名是否相同
{
dp.SetValue(d, sp.GetValue(s, null), null);//获得s对象属性的值复制给d对象的属性
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
public static ColorViewModel Mapper(IColorViewModel s)
{
var d = CopyHelper.Mapper<ColorViewModel, IColorViewModel>(s);
d.LineColor = CopyHelper.Mapper<ColorObject, IColorObject>(s.LineColor);
d.FillColor = CopyHelper.Mapper<ColorObject, IColorObject>(s.FillColor);
d.LineColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.LineColor.GradientStop);
d.FillColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.FillColor.GradientStop);
return d;
}
public static T Mapper<T>(IColorViewModel s) where T: IColorViewModel
{
var d = CopyHelper.Mapper<T, IColorViewModel>(s);
d.LineColor = CopyHelper.Mapper<ColorObjectItem, IColorObject>(s.LineColor);
d.FillColor = CopyHelper.Mapper<ColorObjectItem, IColorObject>(s.FillColor);
d.LineColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.LineColor.GradientStop);
d.FillColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.FillColor.GradientStop);
return d;
}
public static void CopyPropertyValue(IColorViewModel s, IColorViewModel d, string propertyName = null)
{
if (propertyName == "LineColor")
{
CopyPropertyValue(s.LineColor, d.LineColor);
d.LineColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.LineColor.GradientStop);
}
else if (propertyName == "FillColor")
{
CopyPropertyValue(s.FillColor, d.FillColor);
d.FillColor.GradientStop = CopyHelper.DeepCopy<ObservableCollection<GradientStop>>(s.FillColor.GradientStop);
}
else
{
CopyPropertyValue((object)s, (object)d, propertyName);
}
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace AIStudio.Wpf.DiagramDesigner
{
/// <summary>
/// win8下wpf程序测试成功
/// </summary>
public class CursorPointManager
{
#region
[DllImport("user32")]
private static extern bool GetCursorPos(out Point lpPoint);
/// <summary>
/// 获取光标相对于显示器的位置
/// </summary>
/// <returns></returns>
public static Point GetCursorPosition()
{
Point showPoint = new Point();
GetCursorPos(out showPoint);
return showPoint;
}
#endregion
}
}

View File

@@ -0,0 +1,45 @@
using System.ComponentModel;
using System.Threading;
using System.Windows;
namespace AIStudio.Wpf.DiagramDesigner
{
public class DesignerHelper
{
private static bool? _isInDesignMode;
public static bool IsInDesignMode
{
get
{
if (!_isInDesignMode.HasValue)
{
_isInDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(FrameworkElement)).Metadata.DefaultValue;
}
return _isInDesignMode.Value;
}
}
#region IsInMainThread
/// <summary>
/// 是否是在主线程中处理
/// </summary>
public static bool IsInMainThread
{
get
{
if (Thread.CurrentThread.IsBackground || Thread.CurrentThread.IsThreadPoolThread) return false;
if (Thread.CurrentThread.Name == "主线程") return true;
if (Application.Current == null)
return true;
return Thread.CurrentThread == Application.Current.Dispatcher.Thread;
}
}
#endregion
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.DiagramDesigner
{
class DoCommandManager
{
#region Command定义
public class Command
{
string name;
Action action;
Action unDoAction;
Action clearAction;
internal Command(string name, Action action, Action unDoAction, Action clearAction)
{
this.name = name;
this.action = action;
this.unDoAction = unDoAction;
this.clearAction = clearAction;
}
internal void Do() { action(); }
internal void UnDo() { unDoAction(); }
internal void Clear() { if (clearAction != null) clearAction(); }
public override string ToString()
{
return name.ToString();
}
}
#endregion
public Stack<Command> ReDoActionStack { get; private set; }
public Stack<Command> UnDoActionStack { get; private set; }
public int Capacity { get; set; } = 10;
public DoCommandManager()
{
ReDoActionStack = new Stack<Command>();
UnDoActionStack = new Stack<Command>();
}
public void DoNewCommand(string name, Action action, Action unDoAction, Action clearAction = null, bool doit = true)
{
if (UnDoActionStack.Count >= Capacity)
{
//清理
var clear = UnDoActionStack.LastOrDefault();
clear.Clear();
UnDoActionStack = new Stack<Command>(UnDoActionStack.Take(Capacity - 1).Reverse());
}
var cmd = new Command(name, action, unDoAction, clearAction);
UnDoActionStack.Push(cmd);
ReDoActionStack.Clear();
if (doit)
{
cmd.Do();
}
}
public void UnDo()
{
if (!CanUnDo)
return;
var cmd = UnDoActionStack.Pop();
ReDoActionStack.Push(cmd);
cmd.UnDo();
}
public void ReDo()
{
if (!CanReDo)
return;
var cmd = ReDoActionStack.Pop();
UnDoActionStack.Push(cmd);
cmd.Do();
}
public bool CanUnDo { get { return UnDoActionStack.Count != 0; } }
public bool CanReDo { get { return ReDoActionStack.Count != 0; } }
//public IEnumerable<Command> Actions { get { return ReDoActionStack.Reverse().Concat(UnDoActionStack); } }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace AIStudio.Wpf.DiagramDesigner
{
// Wraps info of the dragged object into a class
public class DragObject
{
public Size? DesiredSize { get; set; }
public Type ContentType { get; set; }
public string Icon { get; set; }
public IColorViewModel ColorViewModel { get; set; }
public DesignerItemBase DesignerItem { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
using System;
using System.ComponentModel;
using System.Reflection;
namespace AIStudio.Wpf.DiagramDesigner
{
public static class EnumExtension
{
public static string GetDescription(this Enum value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public class EventToCommandArgs
{
public Object Sender { get; private set; }
public ICommand CommandRan { get; private set; }
public Object CommandParameter { get; private set; }
public EventArgs EventArgs { get; private set; }
public EventToCommandArgs(Object sender, ICommand commandRan, Object commandParameter, EventArgs eventArgs)
{
this.Sender = sender;
this.CommandRan = commandRan;
this.CommandParameter = commandParameter;
this.EventArgs = eventArgs;
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public static partial class Extention
{
/// <summary>
/// 构造函数
/// </summary>
static Extention()
{
JsonSerializerSettings setting = new JsonSerializerSettings();
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
setting.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
setting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
return setting;
});
}
private static BindingFlags _bindingFlags { get; }
= BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static;
/// <summary>
/// 将一个object对象序列化返回一个byte[]
/// </summary>
/// <param name="obj">能序列化的对象</param>
/// <returns></returns>
public static byte[] ToBytes(this object obj)
{
using (MemoryStream ms = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
return ms.GetBuffer();
}
}
/// <summary>
/// 判断是否为Null或者空
/// </summary>
/// <param name="obj">对象</param>
/// <returns></returns>
public static bool IsNullOrEmpty(this object obj)
{
if (obj == null)
return true;
else
{
string objStr = obj.ToString();
return string.IsNullOrEmpty(objStr);
}
}
/// <summary>
/// 将对象序列化成Json字符串
/// </summary>
/// <param name="obj">需要序列化的对象</param>
/// <returns></returns>
public static string ToJson(this object obj)
{
return JsonConvert.SerializeObject(obj);
}
public static JsonSerializerSettings Settings { get; set; } = new JsonSerializerSettings
{
DateFormatString = "yyyy-MM-dd HH:mm:ss.fff",
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore,
};
public static string ToStandardTimeFormatJson(this object obj)
{
return JsonConvert.SerializeObject(obj, Settings);
}
/// <summary>
/// 实体类转json数据速度快
/// </summary>
/// <param name="t">实体类</param>
/// <returns></returns>
public static string EntityToJson(this object t)
{
if (t == null)
return null;
string jsonStr = "";
jsonStr += "{";
PropertyInfo[] infos = t.GetType().GetProperties();
for (int i = 0; i < infos.Length; i++)
{
jsonStr = jsonStr + "\"" + infos[i].Name + "\":\"" + infos[i].GetValue(t).ToString() + "\"";
if (i != infos.Length - 1)
jsonStr += ",";
}
jsonStr += "}";
return jsonStr;
}
///// <summary>
///// 深复制
///// </summary>
///// <typeparam name="T">类型</typeparam>
///// <param name="obj">对象</param>
///// <returns></returns>
//public static T DeepClone<T>(this T obj) where T : class
//{
// if (obj == null)
// return null;
// return obj.ToJson().ToObject<T>();
//}
/// <summary>
/// 将对象序列化为XML字符串
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="obj">对象</param>
/// <returns></returns>
public static string ToXmlStr<T>(this T obj)
{
var jsonStr = obj.ToJson();
var xmlDoc = JsonConvert.DeserializeXmlNode(jsonStr);
string xmlDocStr = xmlDoc.InnerXml;
return xmlDocStr;
}
/// <summary>
/// 将对象序列化为XML字符串
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="obj">对象</param>
/// <param name="rootNodeName">根节点名(建议设为xml)</param>
/// <returns></returns>
public static string ToXmlStr<T>(this T obj, string rootNodeName)
{
var jsonStr = obj.ToJson();
var xmlDoc = JsonConvert.DeserializeXmlNode(jsonStr, rootNodeName);
string xmlDocStr = xmlDoc.InnerXml;
return xmlDocStr;
}
/// <summary>
/// 是否拥有某属性
/// </summary>
/// <param name="obj">对象</param>
/// <param name="propertyName">属性名</param>
/// <returns></returns>
public static bool ContainsProperty(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName, _bindingFlags) != null;
}
/// <summary>
/// 获取某属性值
/// </summary>
/// <param name="obj">对象</param>
/// <param name="propertyName">属性名</param>
/// <returns></returns>
public static object GetPropertyValue(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName, _bindingFlags).GetValue(obj);
}
/// <summary>
/// 设置某属性值
/// </summary>
/// <param name="obj">对象</param>
/// <param name="propertyName">属性名</param>
/// <param name="value">值</param>
/// <returns></returns>
public static void SetPropertyValue(this object obj, string propertyName, object value)
{
obj.GetType().GetProperty(propertyName, _bindingFlags).SetValue(obj, value);
}
/// <summary>
/// 是否拥有某字段
/// </summary>
/// <param name="obj">对象</param>
/// <param name="fieldName">字段名</param>
/// <returns></returns>
public static bool ContainsField(this object obj, string fieldName)
{
return obj.GetType().GetField(fieldName, _bindingFlags) != null;
}
/// <summary>
/// 获取某字段值
/// </summary>
/// <param name="obj">对象</param>
/// <param name="fieldName">字段名</param>
/// <returns></returns>
public static object GetGetFieldValue(this object obj, string fieldName)
{
return obj.GetType().GetField(fieldName, _bindingFlags).GetValue(obj);
}
/// <summary>
/// 设置某字段值
/// </summary>
/// <param name="obj">对象</param>
/// <param name="fieldName">字段名</param>
/// <param name="value">值</param>
/// <returns></returns>
public static void SetFieldValue(this object obj, string fieldName, object value)
{
obj.GetType().GetField(fieldName, _bindingFlags).SetValue(obj, value);
}
///// <summary>
///// 改变实体类型
///// </summary>
///// <param name="obj">对象</param>
///// <param name="targetType">目标类型</param>
///// <returns></returns>
//public static object ChangeType(this object obj, Type targetType)
//{
// return obj.ToJson().ToObject(targetType);
//}
///// <summary>
///// 改变实体类型
///// </summary>
///// <typeparam name="T">目标泛型</typeparam>
///// <param name="obj">对象</param>
///// <returns></returns>
//public static T ChangeType<T>(this object obj)
//{
// return obj.ToJson().ToObject<T>();
//}
/// <summary>
/// 改变类型
/// </summary>
/// <param name="obj">原对象</param>
/// <param name="targetType">目标类型</param>
/// <returns></returns>
public static object ChangeType_ByConvert(this object obj, Type targetType)
{
object resObj;
if (targetType.IsGenericType && targetType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
NullableConverter newNullableConverter = new NullableConverter(targetType);
resObj = newNullableConverter.ConvertFrom(obj);
}
else
{
resObj = Convert.ChangeType(obj, targetType);
}
return resObj;
}
}
}

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace AIStudio.Wpf.DiagramDesigner
{
public interface IPathFinder
{
List<Point> GetConnectionLine(ConnectorInfo source, ConnectorInfo sink, bool showLastLine, bool sourceInnerPoint = false);
List<Point> GetConnectionLine(ConnectorInfo source, Point sinkPoint, ConnectorOrientation preferredOrientation, bool showLastLine, bool isInnerPoint = false);
}
}

View File

@@ -0,0 +1,697 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace AIStudio.Wpf.DiagramDesigner
{
// Note: I couldn't find a useful open source library that does
// orthogonal routing so started to write something on my own.
// Categorize this as a quick and dirty short term solution.
// I will keep on searching.
// Helper class to provide an orthogonal connection path
public class OrthogonalPathFinder : IPathFinder
{
private const int const_margin = 20;
public List<Point> GetConnectionLine(ConnectorInfo source, ConnectorInfo sink, bool showLastLine, bool sourceInnerPoint = false)
{
List<Point> linePoints = new List<Point>();
int margin1 = sourceInnerPoint ? 0 : const_margin;
int margin2 = const_margin;
Rect rectSource = GetRectWithMargin(source, margin1);
Rect rectSink = GetRectWithMargin(sink, margin2);
Point startPoint = GetOffsetPoint(source, rectSource, sourceInnerPoint);
Point endPoint = GetOffsetPoint(sink, rectSink);
linePoints.Add(startPoint);
Point currentPoint = startPoint;
if (!rectSink.Contains(currentPoint) && !rectSource.Contains(endPoint))
{
while (true)
{
#region source node
if (IsPointVisible(currentPoint, endPoint, new Rect[] { rectSource, rectSink }))
{
linePoints.Add(endPoint);
currentPoint = endPoint;
break;
}
Point neighbour = GetNearestVisibleNeighborSink(currentPoint, endPoint, sink, rectSource, rectSink);
if (!double.IsNaN(neighbour.X))
{
linePoints.Add(neighbour);
linePoints.Add(endPoint);
currentPoint = endPoint;
break;
}
if (currentPoint == startPoint)
{
bool flag;
Point n = GetNearestNeighborSource(source, endPoint, rectSource, rectSink, out flag, sourceInnerPoint);
if (linePoints.Contains(n))
{
break;
}
linePoints.Add(n);
currentPoint = n;
if (!IsRectVisible(currentPoint, rectSink, new Rect[] { rectSource }))
{
Point n1, n2;
GetOppositeCorners(source.Orientation, rectSource, out n1, out n2, sourceInnerPoint);
if (flag)
{
linePoints.Add(n1);
currentPoint = n1;
}
else
{
linePoints.Add(n2);
currentPoint = n2;
}
if (!IsRectVisible(currentPoint, rectSink, new Rect[] { rectSource }))
{
if (flag)
{
linePoints.Add(n2);
currentPoint = n2;
}
else
{
linePoints.Add(n1);
currentPoint = n1;
}
}
}
}
#endregion
#region sink node
else // from here on we jump to the sink node
{
Point n1, n2; // neighbour corner
Point s1, s2; // opposite corner
GetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);
GetOppositeCorners(sink.Orientation, rectSink, out n1, out n2);
bool n1Visible = IsPointVisible(currentPoint, n1, new Rect[] { rectSource, rectSink });
bool n2Visible = IsPointVisible(currentPoint, n2, new Rect[] { rectSource, rectSink });
if (n1Visible && n2Visible)
{
if (rectSource.Contains(n1))
{
linePoints.Add(n2);
if (rectSource.Contains(s2))
{
linePoints.Add(n1);
linePoints.Add(s1);
}
else
linePoints.Add(s2);
linePoints.Add(endPoint);
currentPoint = endPoint;
break;
}
if (rectSource.Contains(n2))
{
linePoints.Add(n1);
if (rectSource.Contains(s1))
{
linePoints.Add(n2);
linePoints.Add(s2);
}
else
linePoints.Add(s1);
linePoints.Add(endPoint);
currentPoint = endPoint;
break;
}
if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
{
linePoints.Add(n1);
if (rectSource.Contains(s1))
{
linePoints.Add(n2);
linePoints.Add(s2);
}
else
linePoints.Add(s1);
linePoints.Add(endPoint);
currentPoint = endPoint;
break;
}
else
{
linePoints.Add(n2);
if (rectSource.Contains(s2))
{
linePoints.Add(n1);
linePoints.Add(s1);
}
else
linePoints.Add(s2);
linePoints.Add(endPoint);
currentPoint = endPoint;
break;
}
}
else if (n1Visible)
{
linePoints.Add(n1);
if (rectSource.Contains(s1))
{
linePoints.Add(n2);
linePoints.Add(s2);
}
else
linePoints.Add(s1);
linePoints.Add(endPoint);
currentPoint = endPoint;
break;
}
else
{
linePoints.Add(n2);
if (rectSource.Contains(s2))
{
linePoints.Add(n1);
linePoints.Add(s1);
}
else
linePoints.Add(s2);
linePoints.Add(endPoint);
currentPoint = endPoint;
break;
}
}
#endregion
}
}
else
{
linePoints.Add(endPoint);
}
linePoints = OptimizeLinePoints(linePoints, new Rect[] { rectSource, rectSink }, source.Orientation, sink.Orientation);
CheckPathEnd(source, sink, showLastLine, linePoints, sourceInnerPoint);
return linePoints;
}
public List<Point> GetConnectionLine(ConnectorInfo source, Point sinkPoint, ConnectorOrientation preferredOrientation, bool showLastLine, bool isInnerPoint = false)
{
List<Point> linePoints = new List<Point>();
int margin = isInnerPoint ? 0 : const_margin;
Rect rectSource = GetRectWithMargin(source, margin);
Point startPoint = GetOffsetPoint(source, rectSource, isInnerPoint);
Point endPoint = sinkPoint;
linePoints.Add(startPoint);
Point currentPoint = startPoint;
if (!rectSource.Contains(endPoint))
{
while (true)
{
if (IsPointVisible(currentPoint, endPoint, new Rect[] { rectSource }))
{
linePoints.Add(endPoint);
break;
}
bool sideFlag;
Point n = GetNearestNeighborSource(source, endPoint, rectSource, out sideFlag, isInnerPoint);
linePoints.Add(n);
currentPoint = n;
if (IsPointVisible(currentPoint, endPoint, new Rect[] { rectSource }))
{
linePoints.Add(endPoint);
break;
}
else
{
Point n1, n2;
GetOppositeCorners(source.Orientation, rectSource, out n1, out n2, isInnerPoint);
if (sideFlag)
linePoints.Add(n1);
else
linePoints.Add(n2);
linePoints.Add(endPoint);
break;
}
}
}
else
{
linePoints.Add(endPoint);
}
if (preferredOrientation != ConnectorOrientation.None)
linePoints = OptimizeLinePoints(linePoints, new Rect[] { rectSource }, source.Orientation, preferredOrientation);
else
linePoints = OptimizeLinePoints(linePoints, new Rect[] { rectSource }, source.Orientation, GetOpositeOrientation(source.Orientation));
if (!showLastLine)
{
linePoints.Insert(0, source.Position);
}
return linePoints;
}
private static List<Point> OptimizeLinePoints(List<Point> linePoints, Rect[] rectangles, ConnectorOrientation sourceOrientation, ConnectorOrientation sinkOrientation)
{
List<Point> points = new List<Point>();
int cut = 0;
for (int i = 0; i < linePoints.Count; i++)
{
if (i >= cut)
{
for (int k = linePoints.Count - 1; k > i; k--)
{
if (IsPointVisible(linePoints[i], linePoints[k], rectangles))
{
cut = k;
break;
}
}
points.Add(linePoints[i]);
}
}
#region Line
for (int j = 0; j < points.Count - 1; j++)
{
if (points[j].X != points[j + 1].X && points[j].Y != points[j + 1].Y)
{
ConnectorOrientation orientationFrom;
ConnectorOrientation orientationTo;
// orientation from point
if (j == 0)
orientationFrom = sourceOrientation;
else
orientationFrom = GetOrientation(points[j], points[j - 1]);
// orientation to pint
if (j == points.Count - 2)
orientationTo = sinkOrientation;
else
orientationTo = GetOrientation(points[j + 1], points[j + 2]);
if ((orientationFrom == ConnectorOrientation.Left || orientationFrom == ConnectorOrientation.Right) &&
(orientationTo == ConnectorOrientation.Left || orientationTo == ConnectorOrientation.Right))
{
double centerX = Math.Min(points[j].X, points[j + 1].X) + Math.Abs(points[j].X - points[j + 1].X) / 2;
points.Insert(j + 1, new Point(centerX, points[j].Y));
points.Insert(j + 2, new Point(centerX, points[j + 2].Y));
if (points.Count - 1 > j + 3)
points.RemoveAt(j + 3);
return points;
}
if ((orientationFrom == ConnectorOrientation.Top || orientationFrom == ConnectorOrientation.Bottom) &&
(orientationTo == ConnectorOrientation.Top || orientationTo == ConnectorOrientation.Bottom))
{
double centerY = Math.Min(points[j].Y, points[j + 1].Y) + Math.Abs(points[j].Y - points[j + 1].Y) / 2;
points.Insert(j + 1, new Point(points[j].X, centerY));
points.Insert(j + 2, new Point(points[j + 2].X, centerY));
if (points.Count - 1 > j + 3)
points.RemoveAt(j + 3);
return points;
}
if ((orientationFrom == ConnectorOrientation.Left || orientationFrom == ConnectorOrientation.Right) &&
(orientationTo == ConnectorOrientation.Top || orientationTo == ConnectorOrientation.Bottom))
{
points.Insert(j + 1, new Point(points[j + 1].X, points[j].Y));
return points;
}
if ((orientationFrom == ConnectorOrientation.Top || orientationFrom == ConnectorOrientation.Bottom) &&
(orientationTo == ConnectorOrientation.Left || orientationTo == ConnectorOrientation.Right))
{
points.Insert(j + 1, new Point(points[j].X, points[j + 1].Y));
return points;
}
}
}
#endregion
return points;
}
private static ConnectorOrientation GetOrientation(Point p1, Point p2)
{
if (p1.X == p2.X)
{
if (p1.Y >= p2.Y)
return ConnectorOrientation.Bottom;
else
return ConnectorOrientation.Top;
}
else if (p1.Y == p2.Y)
{
if (p1.X >= p2.X)
return ConnectorOrientation.Right;
else
return ConnectorOrientation.Left;
}
throw new Exception("Failed to retrieve orientation");
}
private static Orientation GetOrientation(ConnectorOrientation sourceOrientation, bool isInnerPoint)
{
if (isInnerPoint)
{
return Orientation.Vertical;
}
switch (sourceOrientation)
{
case ConnectorOrientation.Left:
return Orientation.Horizontal;
case ConnectorOrientation.Top:
return Orientation.Vertical;
case ConnectorOrientation.Right:
return Orientation.Horizontal;
case ConnectorOrientation.Bottom:
return Orientation.Vertical;
default:
throw new Exception("Unknown ConnectorOrientation");
}
}
private static Point GetNearestNeighborSource(ConnectorInfo source, Point endPoint, Rect rectSource, Rect rectSink, out bool flag, bool isInnerPoint)
{
Point n1, n2; // neighbors
GetNeighborCorners(source.Orientation, rectSource, out n1, out n2, isInnerPoint);
if (rectSink.Contains(n1))
{
flag = false;
return n2;
}
if (rectSink.Contains(n2))
{
flag = true;
return n1;
}
if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
{
flag = true;
return n1;
}
else
{
flag = false;
return n2;
}
}
private static Point GetNearestNeighborSource(ConnectorInfo source, Point endPoint, Rect rectSource, out bool flag, bool isInnerPoint)
{
Point n1, n2; // neighbors
GetNeighborCorners(source.Orientation, rectSource, out n1, out n2, isInnerPoint);
if ((Distance(n1, endPoint) <= Distance(n2, endPoint)))
{
flag = true;
return n1;
}
else
{
flag = false;
return n2;
}
}
private static Point GetNearestVisibleNeighborSink(Point currentPoint, Point endPoint, ConnectorInfo sink, Rect rectSource, Rect rectSink)
{
Point s1, s2; // neighbors on sink side
GetNeighborCorners(sink.Orientation, rectSink, out s1, out s2);
bool flag1 = IsPointVisible(currentPoint, s1, new Rect[] { rectSource, rectSink });
bool flag2 = IsPointVisible(currentPoint, s2, new Rect[] { rectSource, rectSink });
if (flag1) // s1 visible
{
if (flag2) // s1 and s2 visible
{
if (rectSink.Contains(s1))
return s2;
if (rectSink.Contains(s2))
return s1;
if ((Distance(s1, endPoint) <= Distance(s2, endPoint)))
return s1;
else
return s2;
}
else
{
return s1;
}
}
else // s1 not visible
{
if (flag2) // only s2 visible
{
return s2;
}
else // s1 and s2 not visible
{
return new Point(double.NaN, double.NaN);
}
}
}
private static bool IsPointVisible(Point fromPoint, Point targetPoint, Rect[] rectangles)
{
foreach (Rect rect in rectangles)
{
if (RectangleIntersectsLine(rect, fromPoint, targetPoint))
return false;
}
return true;
}
private static bool IsRectVisible(Point fromPoint, Rect targetRect, Rect[] rectangles)
{
if (IsPointVisible(fromPoint, targetRect.TopLeft, rectangles))
return true;
if (IsPointVisible(fromPoint, targetRect.TopRight, rectangles))
return true;
if (IsPointVisible(fromPoint, targetRect.BottomLeft, rectangles))
return true;
if (IsPointVisible(fromPoint, targetRect.BottomRight, rectangles))
return true;
return false;
}
private static bool RectangleIntersectsLine(Rect rect, Point startPoint, Point endPoint)
{
rect.Inflate(-1, -1);
return rect.IntersectsWith(new Rect(startPoint, endPoint));
}
private static void GetOppositeCorners(ConnectorOrientation orientation, Rect rect, out Point n1, out Point n2, bool isInnerPoint = false)
{
if (isInnerPoint)
{
n1 = rect.Location; n2 = rect.Location;
return;
}
switch (orientation)
{
case ConnectorOrientation.Left:
n1 = rect.TopRight; n2 = rect.BottomRight;
break;
case ConnectorOrientation.Top:
n1 = rect.BottomLeft; n2 = rect.BottomRight;
break;
case ConnectorOrientation.Right:
n1 = rect.TopLeft; n2 = rect.BottomLeft;
break;
case ConnectorOrientation.Bottom:
n1 = rect.TopLeft; n2 = rect.TopRight;
break;
default:
throw new Exception("No opposite corners found!");
}
}
private static void GetNeighborCorners(ConnectorOrientation orientation, Rect rect, out Point n1, out Point n2, bool isInnerPoint = false)
{
if (isInnerPoint)
{
n1 = rect.Location; n2 = rect.Location;
return;
}
switch (orientation)
{
case ConnectorOrientation.Left:
n1 = rect.TopLeft; n2 = rect.BottomLeft;
break;
case ConnectorOrientation.Top:
n1 = rect.TopLeft; n2 = rect.TopRight;
break;
case ConnectorOrientation.Right:
n1 = rect.TopRight; n2 = rect.BottomRight;
break;
case ConnectorOrientation.Bottom:
n1 = rect.BottomLeft; n2 = rect.BottomRight;
break;
default:
throw new Exception("No neighour corners found!");
}
}
private static double Distance(Point p1, Point p2)
{
return Point.Subtract(p1, p2).Length;
}
private static Rect GetRectWithMargin(ConnectorInfo connectorThumb, double margin)
{
Rect rect = new Rect(connectorThumb.DesignerItemLeft,
connectorThumb.DesignerItemTop,
0,
0);
rect.Inflate(margin, margin);
return rect;
}
private static Point GetOffsetPoint(ConnectorInfo connector, Rect rect, bool isInnerPoint = false)
{
Point offsetPoint = new Point();
if (isInnerPoint)
{
offsetPoint = new Point(connector.Position.X, connector.Position.Y);
return offsetPoint;
}
switch (connector.Orientation)
{
case ConnectorOrientation.Left:
offsetPoint = new Point(rect.Left, connector.Position.Y);
break;
case ConnectorOrientation.Top:
offsetPoint = new Point(connector.Position.X, rect.Top);
break;
case ConnectorOrientation.Right:
offsetPoint = new Point(rect.Right, connector.Position.Y);
break;
case ConnectorOrientation.Bottom:
offsetPoint = new Point(connector.Position.X, rect.Bottom);
break;
default:
break;
}
return offsetPoint;
}
private static void CheckPathEnd(ConnectorInfo source, ConnectorInfo sink, bool showLastLine, List<Point> linePoints, bool sourceInnerPoint)
{
if (showLastLine)
{
Point startPoint = new Point(0, 0);
Point endPoint = new Point(0, 0);
double marginPath = 15;
switch (source.Orientation)
{
case ConnectorOrientation.Left:
startPoint = new Point(source.Position.X - marginPath, source.Position.Y);
break;
case ConnectorOrientation.Top:
startPoint = new Point(source.Position.X, source.Position.Y - marginPath);
break;
case ConnectorOrientation.Right:
startPoint = new Point(source.Position.X + marginPath, source.Position.Y);
break;
case ConnectorOrientation.Bottom:
startPoint = new Point(source.Position.X, source.Position.Y + marginPath);
break;
default:
break;
}
if (sourceInnerPoint)
{
startPoint = new Point(source.Position.X, source.Position.Y);
}
switch (sink.Orientation)
{
case ConnectorOrientation.Left:
endPoint = new Point(sink.Position.X - marginPath, sink.Position.Y);
break;
case ConnectorOrientation.Top:
endPoint = new Point(sink.Position.X, sink.Position.Y - marginPath);
break;
case ConnectorOrientation.Right:
endPoint = new Point(sink.Position.X + marginPath, sink.Position.Y);
break;
case ConnectorOrientation.Bottom:
endPoint = new Point(sink.Position.X, sink.Position.Y + marginPath);
break;
default:
break;
}
linePoints.Insert(0, startPoint);
linePoints.Add(endPoint);
}
else
{
linePoints.Insert(0, source.Position);
linePoints.Add(sink.Position);
}
}
private static ConnectorOrientation GetOpositeOrientation(ConnectorOrientation connectorOrientation)
{
switch (connectorOrientation)
{
case ConnectorOrientation.Left:
return ConnectorOrientation.Right;
case ConnectorOrientation.Top:
return ConnectorOrientation.Bottom;
case ConnectorOrientation.Right:
return ConnectorOrientation.Left;
case ConnectorOrientation.Bottom:
return ConnectorOrientation.Top;
default:
return ConnectorOrientation.Top;
}
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace AIStudio.Wpf.DiagramDesigner
{
public class PointHelper
{
public static Point GetPointForConnector(FullyCreatedConnectorInfo connector)
{
Point point = new Point();
if (connector.IsInnerPoint)
{
point = new Point(connector.DataItem.Left + connector.DataItem.ItemWidth * connector.XRatio,
connector.DataItem.Top + connector.DataItem.ItemHeight * connector.YRatio);
}
else
{
switch (connector.Orientation)
{
case ConnectorOrientation.Top:
point = new Point(connector.DataItem.Left + (connector.DataItem.ItemWidth / 2), connector.DataItem.Top);
break;
case ConnectorOrientation.Bottom:
point = new Point(connector.DataItem.Left + (connector.DataItem.ItemWidth / 2), (connector.DataItem.Top + connector.DataItem.ItemHeight));
break;
case ConnectorOrientation.Right:
point = new Point(connector.DataItem.Left + connector.DataItem.ItemWidth, connector.DataItem.Top + (connector.DataItem.ItemHeight / 2));
break;
case ConnectorOrientation.Left:
point = new Point(connector.DataItem.Left, connector.DataItem.Top + (connector.DataItem.ItemHeight / 2));
break;
}
}
return point;
}
}
}

View File

@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Media;
namespace AIStudio.Wpf.DiagramDesigner
{
public class SegmentHelper
{
/// <summary>
/// 获得贝塞尔曲线
/// </summary>
/// <param name="currentPt">当前点</param>
/// <param name="lastPt">上一个点</param>
/// <param name="nextPt1">下一个点1</param>
/// <param name="nextPt2">下一个点2</param>
/// <returns></returns>
public static BezierSegment GetBezierSegment(Point currentPt, Point lastPt, Point nextPt1, Point nextPt2)
{
//计算中点
var lastC = GetCenterPoint(lastPt, currentPt);
var nextC1 = GetCenterPoint(currentPt, nextPt1); //贝塞尔控制点
var nextC2 = GetCenterPoint(nextPt1, nextPt2);
//计算相邻中点连线跟目的点的垂足
//效果并不算太好,因为可能点在两个线上或者线的延长线上,计算会有误差
//所以就直接使用中点平移方法。
//var C1 = GetFootPoint(lastC, nextC1, currentPt);
//var C2 = GetFootPoint(nextC1, nextC2, nextPt1);
//计算“相邻中点”的中点
var c1 = GetCenterPoint(lastC, nextC1);
var c2 = GetCenterPoint(nextC1, nextC2);
//计算【"中点"的中点】需要的点位移
var controlPtOffset1 = currentPt - c1;
var controlPtOffset2 = nextPt1 - c2;
//移动控制点
var controlPt1 = nextC1 + controlPtOffset1;
var controlPt2 = nextC1 + controlPtOffset2;
//如果觉得曲线幅度太大,可以将控制点向当前点靠近一定的系数。
controlPt1 = controlPt1 + 0 * (currentPt - controlPt1);
controlPt2 = controlPt2 + 0 * (nextPt1 - controlPt2);
var bzs = new BezierSegment(controlPt1, controlPt2, nextPt1, true);
return bzs;
}
/// <summary>
/// 过c点做A和B连线的垂足
/// </summary>
/// <param name="aPoint"></param>
/// <param name="bPoint"></param>
/// <param name="cPoint"></param>
/// <returns></returns>
private static Point GetFootPoint(Point aPoint, Point bPoint, Point cPoint)
{
//设三点坐标是ABCAB构成直线C是线外的点
//三点对边距离是a,b,c,垂足为D
//根据距离推导公式得AD距离是b平方-a平方+c平方/2c
//本人数学不好可能没考虑点c在线ab上的情况
var offsetADist = (Math.Pow(cPoint.X - aPoint.X, 2) + Math.Pow(cPoint.Y - aPoint.Y, 2) - Math.Pow(bPoint.X - cPoint.X, 2) - Math.Pow(bPoint.Y - cPoint.Y, 2) + Math.Pow(aPoint.X - bPoint.X, 2) + Math.Pow(aPoint.Y - bPoint.Y, 2)) / (2 * GetDistance(aPoint, bPoint));
var v = bPoint - aPoint;
var distab = GetDistance(aPoint, bPoint);
var offsetVector = v * offsetADist / distab;
return aPoint + offsetVector;
}
private static Point GetCenterPoint(Point pt1, Point pt2)
{
return new Point((pt1.X + pt2.X) / 2, (pt1.Y + pt2.Y) / 2);
}
private static double GetDistance(Point pt1, Point pt2)
{
return Math.Sqrt(Math.Pow(pt1.X - pt2.X, 2) + Math.Pow(pt1.Y - pt2.Y, 2));
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner.Helpers
{
public class ToolBoxData
{
public string Text { get; protected set; }
public string Icon { get; protected set; }
public Type Type { get; protected set; }
public IColorViewModel ColorViewModel { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public object Addition { get; set; }
public ToolBoxData(string text, string icon, Type type, double width, double height)
{
this.Text = text;
this.Icon = icon;
this.Type = type;
this.Width = width;
this.Height = height;
this.ColorViewModel = new ColorViewModel();
}
}
}

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 AIStudio.Wpf.DiagramDesigner.Helpers
{
//[DebuggerNonUserCode]
public sealed class WeakINPCEventHandler
{
private readonly WeakReference _targetReference;
private readonly MethodInfo _method;
public WeakINPCEventHandler(PropertyChangedEventHandler callback)
{
_method = callback.Method;
_targetReference = new WeakReference(callback.Target, true);
}
//[DebuggerNonUserCode]
public void Handler(object sender, PropertyChangedEventArgs e)
{
var target = _targetReference.Target;
if (target != null)
{
var callback = (Action<object, PropertyChangedEventArgs>)Delegate.CreateDelegate(typeof(Action<object, PropertyChangedEventArgs>), target, _method, true);
if (callback != null)
{
callback(sender, e);
}
}
}
}
}

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 AIStudio.Wpf.DiagramDesigner
{
#region WeakAction Inner Class
/// <summary>
/// This class creates a weak delegate of form Action(Of Object)
/// </summary>
public class WeakAction
{
#region Data
private readonly WeakReference _target;
private readonly Type _ownerType;
private readonly Type _actionType;
private readonly string _methodName;
#endregion
#region Public Properties/Methods
public WeakAction(object target, Type actionType, MethodBase mi)
{
if (target == null)
{
Debug.Assert(mi.IsStatic);
_ownerType = mi.DeclaringType;
}
else
_target = new WeakReference(target);
_methodName = mi.Name;
_actionType = actionType;
}
public Type ActionType
{
get { return _actionType; }
}
public bool HasBeenCollected
{
get
{
return (_ownerType == null && (_target == null || !_target.IsAlive));
}
}
public Delegate GetMethod()
{
if (_ownerType != null)
{
return Delegate.CreateDelegate(_actionType, _ownerType, _methodName);
}
if (_target != null && _target.IsAlive)
{
object target = _target.Target;
if (target != null)
return Delegate.CreateDelegate(_actionType, target, _methodName);
}
return null;
}
#endregion
}
#endregion
/// <summary>
/// This class creates a simple Mediator which loosely connects different objects together.
/// The message handlers are organized using string-based message keys and are held in a WeakReference
/// collection.
/// </summary>
public class Mediator
{
#region Data
static readonly Mediator instance = new Mediator();
static readonly object syncLock = new object();
private readonly Dictionary<object, List<WeakAction>> _registeredHandlers =
new Dictionary<object, List<WeakAction>>();
#endregion
#region Ctor
static Mediator()
{
}
private Mediator()
{
}
#endregion
#region Private Methods
/// <summary>
/// Performs the actual registration of a target
/// </summary>
/// <param name="key">Key to store in dictionary</param>
/// <param name="actionType">Delegate type</param>
/// <param name="handler">Method</param>
private void RegisterHandler(object key, Type actionType, Delegate handler)
{
var action = new WeakAction(handler.Target, actionType, handler.Method);
lock (_registeredHandlers)
{
List<WeakAction> wr;
if (_registeredHandlers.TryGetValue(key, out wr))
{
if (wr.Count > 0)
{
WeakAction wa = wr[0];
if (wa.ActionType != actionType &&
!wa.ActionType.IsAssignableFrom(actionType))
throw new ArgumentException("Invalid key passed to RegisterHandler - existing handler has incompatible parameter type");
}
wr.Add(action);
}
else
{
wr = new List<WeakAction> { action };
_registeredHandlers.Add(key, wr);
}
}
}
/// <summary>
/// Performs the unregistration from a target
/// </summary>
/// <param name="key">Key to store in dictionary</param>
/// <param name="actionType">Delegate type</param>
/// <param name="handler">Method</param>
private void UnregisterHandler(object key, Type actionType, Delegate handler)
{
lock (_registeredHandlers)
{
List<WeakAction> wr;
if (_registeredHandlers.TryGetValue(key, out wr))
{
wr.RemoveAll(wa => handler == wa.GetMethod() && actionType == wa.ActionType);
if (wr.Count == 0)
_registeredHandlers.Remove(key);
}
}
}
/// <summary>
/// This method broadcasts a message to all message targets for a given
/// message key and passes a parameter.
/// </summary>
/// <param name="key">Message key</param>
/// <param name="message">Message parameter</param>
/// <returns>True/False if any handlers were invoked.</returns>
private bool NotifyColleagues(object key, object message)
{
List<WeakAction> wr;
List<WeakAction> wrCopy = new List<WeakAction>();
lock (_registeredHandlers)
{
if (!_registeredHandlers.TryGetValue(key, out wr))
return false;
else
{
foreach (var weakRe in wr)
{
wrCopy.Add(weakRe);
}
}
}
foreach (var cb in wrCopy)
{
Delegate action = cb.GetMethod();
if (action != null)
action.DynamicInvoke(message);
}
lock (_registeredHandlers)
{
wr.RemoveAll(wa => wa.HasBeenCollected);
}
return true;
}
#endregion
#region Public Properties/Methods
/// <summary>
/// Singleton Instance
/// </summary>
public static Mediator Instance
{
get
{
return instance;
}
}
/// <summary>
/// This registers a Type with the mediator. Any methods decorated with <seealso cref="MediatorMessageSinkAttribute"/> will be
/// registered as target method handlers for the given message key.
/// </summary>
/// <param name="view">Object to register</param>
public void Register(object view)
{
// Look at all instance/static methods on this object type.
foreach (var mi in view.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
// See if we have a target attribute - if so, register the method as a handler.
foreach (var att in mi.GetCustomAttributes(typeof(MediatorMessageSinkAttribute), true))
{
var mha = (MediatorMessageSinkAttribute)att;
var pi = mi.GetParameters();
if (pi.Length != 1)
throw new InvalidCastException("Cannot cast " + mi.Name + " to Action<T> delegate type.");
Type actionType = typeof(Action<>).MakeGenericType(pi[0].ParameterType);
object key = (mha.MessageKey) ?? actionType;
if (mi.IsStatic)
RegisterHandler(key, actionType, Delegate.CreateDelegate(actionType, mi));
else
RegisterHandler(key, actionType, Delegate.CreateDelegate(actionType, view, mi.Name));
}
}
}
/// <summary>
/// This method unregisters a type from the message mediator.
/// </summary>
/// <param name="view">Object to unregister</param>
public void Unregister(object view)
{
foreach (var mi in view.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
foreach (var att in mi.GetCustomAttributes(typeof(MediatorMessageSinkAttribute), true))
{
var mha = (MediatorMessageSinkAttribute)att;
var pi = mi.GetParameters();
if (pi.Length != 1)
throw new InvalidCastException("Cannot cast " + mi.Name + " to Action<T> delegate type.");
Type actionType = typeof(Action<>).MakeGenericType(pi[0].ParameterType);
object key = (mha.MessageKey) ?? actionType;
if (mi.IsStatic)
UnregisterHandler(key, actionType, Delegate.CreateDelegate(actionType, mi));
else
UnregisterHandler(key, actionType, Delegate.CreateDelegate(actionType, view, mi.Name));
}
}
}
/// <summary>
/// This registers a specific method as a message handler for a specific type.
/// </summary>
/// <param name="key">Message key</param>
/// <param name="handler">Handler method</param>
public void RegisterHandler<T>(string key, Action<T> handler)
{
RegisterHandler(key, handler.GetType(), handler);
}
/// <summary>
/// This registers a specific method as a message handler for a specific type.
/// </summary>
/// <param name="handler">Handler method</param>
public void RegisterHandler<T>(Action<T> handler)
{
RegisterHandler(typeof(Action<T>), handler.GetType(), handler);
}
/// <summary>
/// This unregisters a method as a handler.
/// </summary>
/// <param name="key">Message key</param>
/// <param name="handler">Handler</param>
public void UnregisterHandler<T>(string key, Action<T> handler)
{
UnregisterHandler(key, handler.GetType(), handler);
}
/// <summary>
/// This unregisters a method as a handler for a specific type
/// </summary>
/// <param name="handler">Handler</param>
public void UnregisterHandler<T>(Action<T> handler)
{
UnregisterHandler(typeof(Action<T>), handler.GetType(), handler);
}
/// <summary>
/// This method broadcasts a message to all message targets for a given
/// message key and passes a parameter.
/// </summary>
/// <param name="key">Message key</param>
/// <param name="message">Message parameter</param>
/// <returns>True/False if any handlers were invoked.</returns>
public bool NotifyColleagues<T>(string key, T message)
{
return NotifyColleagues((object)key, message);
}
/// <summary>
/// This method broadcasts a message to all message targets for a given parameter type.
/// If a derived type is passed, any handlers for interfaces or base types will also be
/// invoked.
/// </summary>
/// <param name="message">Message parameter</param>
/// <returns>True/False if any handlers were invoked.</returns>
public bool NotifyColleagues<T>(T message)
{
Type actionType = typeof(Action<>).MakeGenericType(typeof(T));
var keyList = from key in _registeredHandlers.Keys
where key is Type && ((Type)key).IsAssignableFrom(actionType)
select key;
bool rc = false;
foreach (var key in keyList)
rc |= NotifyColleagues(key, message);
return rc;
}
/// <summary>
/// This method broadcasts a message to all message targets for a given
/// message key and passes a parameter. The message targets are all called
/// asynchronously and any resulting exceptions are ignored.
/// </summary>
/// <param name="key">Message key</param>
/// <param name="message">Message parameter</param>
public void NotifyColleaguesAsync<T>(string key, T message)
{
Func<string, T, bool> smaFunc = NotifyColleagues;
smaFunc.BeginInvoke(key, message, ia =>
{
try { smaFunc.EndInvoke(ia); }
catch { }
}, null);
}
/// <summary>
/// This method broadcasts a message to all message targets for a given parameter type.
/// If a derived type is passed, any handlers for interfaces or base types will also be
/// invoked. The message targets are all called asynchronously and any resulting exceptions
/// are ignored.
/// </summary>
/// <param name="message">Message parameter</param>
public void NotifyColleaguesAsync<T>(T message)
{
Func<T, bool> smaFunc = NotifyColleagues;
smaFunc.BeginInvoke(message, ia =>
{
try { smaFunc.EndInvoke(ia); }
catch { }
}, null);
}
#endregion
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
/// <summary>
/// This attribute allows a method to be targeted as a recipient for a message.
/// It requires that the Type is registered with the MessageMediator through the
/// <seealso cref="MessageMediator.Register"/> method
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public sealed class MediatorMessageSinkAttribute : Attribute
{
/// <summary>
/// Message key
/// </summary>
public object MessageKey { get; private set; }
/// <summary>
/// Default constructor
/// </summary>
public MediatorMessageSinkAttribute()
{
MessageKey = null;
}
/// <summary>
/// Constructor that takes a message key
/// </summary>
/// <param name="messageKey">Message Key</param>
public MediatorMessageSinkAttribute(string messageKey)
{
MessageKey = messageKey;
}
}
}

View File

@@ -0,0 +1,108 @@
using AIStudio.Wpf.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Xml.Serialization;
namespace AIStudio.Wpf.DiagramDesigner
{
[Serializable]
[XmlInclude(typeof(ConnectionItem))]
public class ConnectionItem : SelectableDesignerItemBase
{
public ConnectionItem()
{
}
//public ConnectionItem(Guid id, Guid sourceId, ConnectorOrientation sourceOrientation, Type sourceType, double sourceXRatio, double sourceYRatio, bool sourceInnerPoint,
// Guid sinkId, ConnectorOrientation sinkOrientation, Type sinkType, double sinkXRatio, double sinkYRatio, bool sinkInnerPoint,
// int zIndex, bool isGroup, Guid parentId, DrawMode vectorLineDrawMode, ColorViewModel colorViewModel, FontViewModel fontViewModel) : base(id, zIndex, isGroup, parentId, colorViewModel, fontViewModel)
//{
// this.SourceId = sourceId;
// this.SourceOrientation = sourceOrientation;
// this.SourceType = sourceType;
// this.SourceTypeName = sourceType.FullName;
// this.SourceXRatio = sourceXRatio;
// this.SourceYRatio = sourceYRatio;
// this.SourceInnerPoint = sourceInnerPoint;
// this.SinkId = sinkId;
// this.SinkOrientation = sinkOrientation;
// this.SinkType = sinkType;
// this.SinkTypeName = sinkType.FullName;
// this.SinkXRatio = sinkXRatio;
// this.SinkYRatio = sinkYRatio;
// this.SinkInnerPoint = sinkInnerPoint;
// this.VectorLineDrawMode = vectorLineDrawMode;
//}
public ConnectionItem(Guid sourceId, ConnectorOrientation sourceOrientation, Type sourceType, double sourceXRatio, double sourceYRatio, bool sourceInnerPoint,
Guid sinkId, ConnectorOrientation sinkOrientation, Type sinkType, double sinkXRatio, double sinkYRatio, bool sinkInnerPoint, ConnectorViewModel viewmodel) : base(viewmodel)
{
this.SourceId = sourceId;
this.SourceOrientation = sourceOrientation;
this.SourceType = sourceType;
this.SourceTypeName = sourceType.FullName;
this.SourceXRatio = sourceXRatio;
this.SourceYRatio = sourceYRatio;
this.SourceInnerPoint = sourceInnerPoint;
this.SinkId = sinkId;
this.SinkOrientation = sinkOrientation;
this.SinkType = sinkType;
this.SinkTypeName = sinkType.FullName;
this.SinkXRatio = sinkXRatio;
this.SinkYRatio = sinkYRatio;
this.SinkInnerPoint = sinkInnerPoint;
this.VectorLineDrawMode = viewmodel.VectorLineDrawMode;
}
[XmlAttribute]
public Guid SourceId { get; set; }
[XmlAttribute]
public ConnectorOrientation SourceOrientation { get; set; }
[XmlIgnore]
public Type SourceType { get; set; }
[XmlAttribute]
public string SourceTypeName { get; set; }
[XmlAttribute]
public double SourceXRatio { get; set; }
[XmlAttribute]
public double SourceYRatio { get; set; }
[XmlAttribute]
public bool SourceInnerPoint { get; set; }
[XmlAttribute]
public Guid SinkId { get; set; }
[XmlAttribute]
public ConnectorOrientation SinkOrientation { get; set; }
[XmlIgnore]
public Type SinkType { get; set; }
[XmlAttribute]
public string SinkTypeName { get; set; }
[XmlAttribute]
public double SinkXRatio { get; set; }
[XmlAttribute]
public double SinkYRatio { get; set; }
[XmlAttribute]
public bool SinkInnerPoint { get; set; }
[XmlAttribute]
public DrawMode VectorLineDrawMode { get; set; }
}
}

View File

@@ -0,0 +1,23 @@
using AIStudio.Wpf.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ConnectorItem
{
public Guid ParentId { get; set; }
public Guid Id { get; set; }
public double XRatio { get; set; }
public double YRatio { get; set; }
public double ConnectorWidth { get; set; }
public double ConnectorHeight { get; set; }
public ConnectorOrientation Orientation { get; set; }
public bool IsInnerPoint { get; set; }
public ValueTypePoint ValueTypePoint { get; set; }
public double ConnectorValue { get; set; }
}
}

View File

@@ -0,0 +1,72 @@
using AIStudio.Wpf.DiagramDesigner;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Xml.Serialization;
namespace AIStudio.Wpf.DiagramDesigner
{
[Serializable]
[XmlInclude(typeof(DesignerItemBase))]
public class DesignerItemBase : SelectableDesignerItemBase
{
public DesignerItemBase()
{
}
public DesignerItemBase(DesignerItemViewModelBase viewmodel, string reserve = null) : base(viewmodel)
{
this.Left = viewmodel.Left;
this.Top = viewmodel.Top;
this.Angle = viewmodel.Angle;
this.ScaleX = viewmodel.ScaleX;
this.ScaleY = viewmodel.ScaleY;
this.ItemWidth = viewmodel.ItemWidth;
this.ItemHeight = viewmodel.ItemHeight;
this.Icon = viewmodel.Icon;
this.ItemTypeName = viewmodel.GetType().FullName;
this.Margin = viewmodel.Margin;
this.Reserve = reserve;
}
[XmlAttribute]
public double Left { get; set; }
[XmlAttribute]
public double Top { get; set; }
[XmlAttribute]
public double Angle { get; set; }
[XmlAttribute]
public double ScaleX { get; set; }
[XmlAttribute]
public double ScaleY { get; set; }
[XmlAttribute]
public double Margin { get; set; }
[XmlAttribute]
public double ItemWidth { get; set; }
[XmlAttribute]
public double ItemHeight { get; set; }
[XmlAttribute]
public string Icon { get; set; }
[XmlAttribute]
public string Reserve { get; set; }
[XmlAttribute]
public string ItemTypeName { get; set; }
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Xml.Serialization;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ImageDesignerItem : DesignerItemBase
{
public ImageDesignerItem()
{
}
public ImageDesignerItem(ImageItemViewModel item) : base(item)
{
Icon = item.Icon;
Connectors = new List<ConnectorItem>();
foreach (var fullyCreatedConnectorInfo in item.Connectors)
{
ConnectorItem connector = new ConnectorItem()
{
XRatio = fullyCreatedConnectorInfo.XRatio,
YRatio = fullyCreatedConnectorInfo.YRatio,
ConnectorWidth = fullyCreatedConnectorInfo.ConnectorWidth,
ConnectorHeight = fullyCreatedConnectorInfo.ConnectorHeight,
Orientation = fullyCreatedConnectorInfo.Orientation
};
Connectors.Add(connector);
}
}
[XmlArray]
public List<ConnectorItem> Connectors { get; set; }
}
}

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 AIStudio.Wpf.DiagramDesigner
{
public class LogicalGateDesignerItemBase : DesignerItemBase
{
public LogicalGateDesignerItemBase()
{
}
public LogicalGateDesignerItemBase(LogicalGateItemViewModelBase item) : base(item)
{
this.Connectors = new List<ConnectorItem>();
foreach (var fullyCreatedConnectorInfo in item.Connectors)
{
ConnectorItem connector = new ConnectorItem()
{
XRatio = fullyCreatedConnectorInfo.XRatio,
YRatio = fullyCreatedConnectorInfo.YRatio,
ConnectorWidth = fullyCreatedConnectorInfo.ConnectorWidth,
ConnectorHeight = fullyCreatedConnectorInfo.ConnectorHeight,
Orientation = fullyCreatedConnectorInfo.Orientation,
IsInnerPoint = fullyCreatedConnectorInfo.IsInnerPoint,
ValueTypePoint = fullyCreatedConnectorInfo.ValueTypePoint,
ConnectorValue = fullyCreatedConnectorInfo.ConnectorValue
};
this.Connectors.Add(connector);
}
this.OrderNumber = item.OrderNumber;
this.LogicalType = item.LogicalType;
this.Value = item.Value;
this.IsEnabled = item.IsEnabled;
}
[XmlArray]
public List<ConnectorItem> Connectors { get; set; }
[XmlAttribute]
public int OrderNumber { get; set; }
[XmlAttribute]
public double Value { get; set; }
[XmlAttribute]
public LogicalType LogicalType { get; set; }
[XmlAttribute]
public bool IsEnabled { get; set; }
}
}

View File

@@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.Xml.Serialization;
namespace AIStudio.Wpf.DiagramDesigner
{
public class MediaDesignerItem : DesignerItemBase
{
public MediaDesignerItem()
{
}
public MediaDesignerItem(GifImageItemViewModel item) : base(item)
{
Connectors = new List<ConnectorItem>();
foreach (var fullyCreatedConnectorInfo in item.Connectors)
{
ConnectorItem connector = new ConnectorItem()
{
XRatio = fullyCreatedConnectorInfo.XRatio,
YRatio = fullyCreatedConnectorInfo.YRatio,
ConnectorWidth = fullyCreatedConnectorInfo.ConnectorWidth,
ConnectorHeight = fullyCreatedConnectorInfo.ConnectorHeight,
Orientation = fullyCreatedConnectorInfo.Orientation
};
Connectors.Add(connector);
}
}
public MediaDesignerItem(MediaItemViewModel item) : base(item)
{
Connectors = new List<ConnectorItem>();
foreach (var fullyCreatedConnectorInfo in item.Connectors)
{
ConnectorItem connector = new ConnectorItem()
{
XRatio = fullyCreatedConnectorInfo.XRatio,
YRatio = fullyCreatedConnectorInfo.YRatio,
ConnectorWidth = fullyCreatedConnectorInfo.ConnectorWidth,
ConnectorHeight = fullyCreatedConnectorInfo.ConnectorHeight,
Orientation = fullyCreatedConnectorInfo.Orientation
};
Connectors.Add(connector);
}
}
[XmlArray]
public List<ConnectorItem> Connectors { get; set; }
}
}

View File

@@ -0,0 +1,496 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Xml.Serialization;
namespace AIStudio.Wpf.DiagramDesigner
{
public abstract class SelectableDesignerItemBase
{
public SelectableDesignerItemBase()
{
ColorItem = new ColorItem() { LineColor = new ColorObjectItem(), FillColor = new ColorObjectItem() };
FontItem = new FontItem();
}
//public SelectableDesignerItemBase(Guid id, int zIndex, bool isGroup, Guid parentId, IColorViewModel colorViewModel, IFontViewModel fontViewModel)
//{
// this.Id = id;
// this.ZIndex = zIndex;
// this.IsGroup = isGroup;
// this.ParentId = parentId;
// ColorItem = CopyHelper.Mapper<ColorItem>(colorViewModel);
// FontItem = CopyHelper.Mapper<FontItem, IFontViewModel>(fontViewModel);
//}
public SelectableDesignerItemBase(SelectableDesignerItemViewModelBase viewmodel)
{
this.Id = viewmodel.Id;
this.ZIndex = viewmodel.ZIndex;
this.IsGroup = viewmodel.IsGroup;
this.ParentId = viewmodel.ParentId;
this.Text = viewmodel.Text;
ColorItem = CopyHelper.Mapper<ColorItem>(viewmodel.ColorViewModel);
FontItem = CopyHelper.Mapper<FontItem, IFontViewModel>(viewmodel.FontViewModel);
}
[XmlAttribute]
public Guid Id { get; set; }
[XmlAttribute]
public int ZIndex { get; set; }
[XmlAttribute]
public bool IsGroup { get; set; }
[XmlAttribute]
public Guid ParentId { get; set; }
[XmlAttribute]
public string Text { get; set; }
[XmlElement]
public ColorItem ColorItem { get; set; }
[XmlElement]
public FontItem FontItem { get; set; }
}
public class ColorItem : IColorViewModel
{
[XmlIgnore]
public IColorObject LineColor { get; set; }
[JsonIgnore]
[XmlElement("LineColor")]
public ColorObjectItem XmlLineColor
{
get
{
return LineColor as ColorObjectItem;
}
set
{
LineColor = value;
}
}
[XmlIgnore]
public IColorObject FillColor { get; set; }
[JsonIgnore]
[XmlElement("FillColor")]
public ColorObjectItem XmlFillColor
{
get
{
return FillColor as ColorObjectItem;
}
set
{
FillColor = value;
}
}
[XmlIgnore]
public Color ShadowColor { get; set; }
[JsonIgnore]
[XmlElement("ShadowColor")]
public string XmlShadowColor
{
get
{
return SerializeHelper.SerializeColor(ShadowColor);
}
set
{
ShadowColor = SerializeHelper.DeserializeColor(value);
}
}
[XmlAttribute]
public double LineWidth { get; set; }
[XmlAttribute]
public ArrowPathStyle LeftArrowPathStyle { get; set; }
[XmlAttribute]
public ArrowPathStyle RightArrowPathStyle { get; set; }
[XmlAttribute]
public ArrowSizeStyle LeftArrowSizeStyle { get; set; }
[XmlAttribute]
public ArrowSizeStyle RightArrowSizeStyle { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
[XmlInclude(typeof(FontItem))]
public class FontItem : IFontViewModel
{
[XmlIgnore]
public FontWeight FontWeight { get; set; }
[XmlIgnore]
public FontStyle FontStyle { get; set; }
[XmlIgnore]
public FontStretch FontStretch { get; set; }
[XmlAttribute]
public bool Underline { get; set; }
[XmlAttribute]
public bool Strikethrough { get; set; }
[XmlAttribute]
public bool OverLine { get; set; }
[XmlIgnore]
public Color FontColor { get; set; }
[JsonIgnore]
[XmlElement("FontColor")]
public string XmlFontColor
{
get
{
return SerializeHelper.SerializeColor(FontColor);
}
set
{
FontColor = SerializeHelper.DeserializeColor(value);
}
}
[XmlIgnore]
public string FontFamily { get; set; }
[XmlIgnore]
public double FontSize { get; set; }
[XmlIgnore]
public System.Drawing.Font FontObject
{
get
{
var xmlFontStyle = System.Drawing.FontStyle.Regular;
if (FontStyle == FontStyles.Italic)
{
xmlFontStyle |= System.Drawing.FontStyle.Italic;
}
if (FontWeight == FontWeights.Bold)
{
xmlFontStyle |= System.Drawing.FontStyle.Bold;
}
return new System.Drawing.Font(FontFamily, (float)FontSize, xmlFontStyle);
}
set
{
FontFamily = value.FontFamily.Name;
FontSize = value.Size;
var xmlFontStyle = value.Style;
if ((xmlFontStyle & System.Drawing.FontStyle.Italic) == System.Drawing.FontStyle.Italic)
{
FontStyle = FontStyles.Italic;
}
else
{
FontStyle = FontStyles.Normal;
}
if ((xmlFontStyle & System.Drawing.FontStyle.Bold) == System.Drawing.FontStyle.Bold)
{
FontWeight = FontWeights.Bold;
}
else
{
FontWeight = FontWeights.Regular;
}
}
}
[JsonIgnore]
[XmlElement("FontObject")]
public XmlFont XmlFontObject
{
get
{
return SerializeHelper.SerializeFont(FontObject);
}
set
{
FontObject = SerializeHelper.DeserializeFont(value);
}
}
[XmlIgnore]
public Color TextEffectColor { get; set; }
[JsonIgnore]
[XmlElement("TextEffectColor")]
public string XmlTextEffectColor
{
get
{
return SerializeHelper.SerializeColor(TextEffectColor);
}
set
{
TextEffectColor = SerializeHelper.DeserializeColor(value);
}
}
[XmlIgnore]
public Color HighlightColor { get; set; }
[JsonIgnore]
[XmlElement("HighlightColor")]
public string XmlHighlightColor
{
get
{
return SerializeHelper.SerializeColor(HighlightColor);
}
set
{
HighlightColor = SerializeHelper.DeserializeColor(value);
}
}
[XmlAttribute]
public FontCase FontCase { get; set; }
[XmlAttribute]
public HorizontalAlignment HorizontalAlignment { get; set; }
[XmlAttribute]
public VerticalAlignment VerticalAlignment { get; set; }
[XmlAttribute]
public double LineHeight { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
public class SerializeHelper
{
public static string SerializeColor(Color color)
{
return string.Format("{0}:{1}:{2}:{3}", color.A, color.R, color.G, color.B);
}
public static Color DeserializeColor(string color)
{
byte a, r, g, b;
string[] pieces = color.Split(new char[] { ':' });
a = byte.Parse(pieces[0]);
r = byte.Parse(pieces[1]);
g = byte.Parse(pieces[2]);
b = byte.Parse(pieces[3]);
return Color.FromArgb(a, r, g, b);
}
public static GradientStop DeserializeGradientStop(string str)
{
var strList = str.Split('-');
return new GradientStop(DeserializeColor(strList[0]), double.Parse(strList[1]));
}
public static string SerializeColorList(IEnumerable<Color> colors)
{
return string.Join("-", colors.Select(color => string.Format("{0}:{1}:{2}:{3}", color.A, color.R, color.G, color.B)));
}
public static List<Color> DeserializeColorList(string colorstring)
{
List<Color> colorlist = new List<Color>();
var colors = colorstring.Split('-');
foreach (var color in colors)
{
byte a, r, g, b;
string[] pieces = color.Split(new char[] { ':' });
a = byte.Parse(pieces[0]);
r = byte.Parse(pieces[1]);
g = byte.Parse(pieces[2]);
b = byte.Parse(pieces[3]);
colorlist.Add(Color.FromArgb(a, r, g, b));
}
return colorlist;
}
public static XmlFont SerializeFont(System.Drawing.Font font)
{
return new XmlFont(font);
}
public static System.Drawing.Font DeserializeFont(XmlFont font)
{
return font.ToFont();
}
public static string SerializePoint(Point point)
{
return string.Format("{0},{1}", point.X, point.Y);
}
public static Point DeserializePoint(string point)
{
string[] pieces = point.Split(new char[] { ',' });
return new Point(double.Parse(pieces[0]), double.Parse(pieces[1]));
}
public static string SerializeSize(Size size)
{
return string.Format("{0},{1}", size.Width, size.Height);
}
public static Size DeserializeSize(string size)
{
string[] pieces = size.Split(new char[] { ',' });
return new Size(double.Parse(pieces[0]), double.Parse(pieces[1]));
}
}
public struct XmlFont
{
public string FontFamily;
public System.Drawing.GraphicsUnit GraphicsUnit;
public float Size;
public System.Drawing.FontStyle Style;
public XmlFont(System.Drawing.Font f)
{
FontFamily = f.FontFamily.Name;
GraphicsUnit = f.Unit;
Size = f.Size;
Style = f.Style;
}
public System.Drawing.Font ToFont()
{
return new System.Drawing.Font(FontFamily, Size, Style, GraphicsUnit);
}
}
public class ColorObjectItem : IColorObject
{
[XmlAttribute]
public BrushType BrushType { get; set; }
[XmlIgnore]
public Color Color { get; set; }
[JsonIgnore]
[XmlElement("FillColor")]
public string XmlFillColor
{
get
{
return SerializeHelper.SerializeColor(Color);
}
set
{
Color = SerializeHelper.DeserializeColor(value);
}
}
[XmlIgnore]
public ObservableCollection<GradientStop> GradientStop { get; set; }
[JsonIgnore]
[XmlArray("GradientStop")]
public List<string> XmlGradientStop
{
get
{
return GradientStop?.Select(p => SerializeHelper.SerializeColor(p.Color) + "-" + p.Offset).ToList();
}
set
{
GradientStop = new ObservableCollection<GradientStop>(value?.Select(p => SerializeHelper.DeserializeGradientStop(p)));
}
}
[XmlIgnore]
public IEnumerable<double> Offset { get; set; }
[JsonIgnore]
[XmlArray("Offset")]
public List<double> XmlOffset
{
get
{
return Offset?.ToList();
}
set
{
Offset = value;
}
}
[XmlAttribute]
public string Image { get; set; }
[XmlAttribute]
public int SubType { get; set; }
[XmlIgnore]
public Point StartPoint { get; set; }
[JsonIgnore]
[XmlAttribute("StartPoint")]
public string XmlStartPoint
{
get
{
return SerializeHelper.SerializePoint(StartPoint);
}
set
{
StartPoint = SerializeHelper.DeserializePoint(value);
}
}
[XmlIgnore]
public Point EndPoint { get; set; }
[JsonIgnore]
[XmlAttribute("EndPoint")]
public string XmlEndPoint
{
get
{
return SerializeHelper.SerializePoint(EndPoint);
}
set
{
EndPoint = SerializeHelper.DeserializePoint(value);
}
}
[XmlAttribute]
public double Opacity { get; set; }
[XmlAttribute]
public LinearOrientation LinearOrientation { get; set; }
[XmlAttribute]
public RadialOrientation RadialOrientation { get; set; }
[XmlAttribute]
public int Angle { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace AIStudio.Wpf.DiagramDesigner
{
public class ArrowPathData
{
public static readonly List<string> Arrow = new List<string>()
{
"",
"M0,10 L5,0 10,10 z",
"M832 664c0 10.752-3.968 20.096-11.904 28.096C812.096 700.096 802.752 704 792 704l-560 0c-10.816 0-20.16-3.904-28.096-11.904C195.904 684.096 192 674.752 192 664s3.904-20.096 11.904-28.096l280-280C491.84 348.032 501.184 344 512 344c10.752 0 20.096 3.968 28.096 11.904l280 280C828.032 643.904 832 653.248 832 664z",
"M691.626667 682.666667H332.373333a75.093333 75.093333 0 0 1-67.84-42.666667 89.6 89.6 0 0 1 11.093334-94.293333l179.626666-217.6a75.093333 75.093333 0 0 1 113.493334 0l179.626666 217.6A89.6 89.6 0 0 1 759.466667 640a75.093333 75.093333 0 0 1-67.84 42.666667z",
"M171.64288 701.41952a47.18592 47.18592 0 0 1 4.11648-57.344l276.70528-310.12864a79.60576 79.60576 0 0 1 119.05024 0l276.72576 310.10816a47.18592 47.18592 0 0 1 3.072 58.83904c-11.30496 15.29856-32.768 18.45248-47.9232 7.04512l-255.488-192.14336a59.65824 59.65824 0 0 0-71.80288 0l-255.488 192.14336a34.05824 34.05824 0 0 1-48.9472-8.54016z",
"M119.466667 827.733333L512 435.2l392.533333 392.533333 119.466667-119.466666-512-512-512 512z",
"M957.44 772.813L509.952 391.066 66.97 772.608 0 694.886 509.542 256 1024 694.784z",
"M828.47744 660.7872a81.7152 81.7152 0 0 1-62.48448 28.89728 81.73568 81.73568 0 0 1-52.98176-19.47648l-172.46208-146.45248-172.4416 146.45248a81.94048 81.94048 0 0 1-106.06592-124.86656l225.4848-191.50848a81.89952 81.89952 0 0 1 106.06592 0l225.4848 191.50848a81.85856 81.85856 0 0 1 9.40032 115.44576z",
"M256.917333 780.288c-40.725333 40.405333-106.645333 40.512-147.264 0.192l-36.373333-36.096a103.36 103.36 0 0 1 0.085333-146.944l350.421334-347.754667a125.290667 125.290667 0 0 1 176.490666 0l350.4 347.754667a103.466667 103.466667 0 0 1 0.085334 146.944l-36.352 36.096c-40.682667 40.362667-106.56 40.192-147.264-0.192L512.021333 527.104 256.917333 780.288z m225.066667-343.594667a42.666667 42.666667 0 0 1 60.096 0l285.184 283.029334a19.328 19.328 0 0 0 27.029333 0.192l36.352-36.096a18.154667 18.154667 0 0 0-0.064-25.813334L540.16 310.250667a39.957333 39.957333 0 0 0-56.256 0L133.482667 658.005333a18.026667 18.026667 0 0 0-0.085334 25.813334l36.373334 36.096a19.349333 19.349333 0 0 0 27.029333-0.192L481.962667 436.693333z",
"M67.969 562.046c0 23.955 19.441 43.396 43.396 43.396 10.773 0 20.33-4.346 27.937-10.86l0.425 0.425 2.235-2.235c0.044-0.044 0.067-0.063 0.112-0.106l358.336-358.338c6.256-6.239 16.377-6.239 22.61 0l360.685 360.679 0.658-0.659c7.647 6.685 17.356 11.093 28.3 11.093 23.935 0 43.374-19.441 43.374-43.396 0-15.289-8.389-28.084-20.355-35.812-0.724-1.344-0.576-2.983-1.705-4.112l-410.958-410.948c-6.234-6.244-16.354-6.244-22.61 0l-410.95 410.949c-1.279 1.279-1.172 3.108-1.916 4.641-11.522 7.794-19.571 20.336-19.571 35.283zM67.969 874.116c0 23.955 19.441 43.394 43.396 43.394 10.773 0 20.33-4.342 27.937-10.855l0.425 0.425 2.235-2.235c0.044-0.045 0.067-0.065 0.112-0.109l358.336-358.339c6.256-6.239 16.377-6.239 22.61 0l360.685 360.684 0.658-0.66c7.647 6.685 17.356 11.091 28.3 11.091 23.935 0 43.374-19.439 43.374-43.394 0-15.289-8.389-28.087-20.355-35.815-0.724-1.341-0.576-2.98-1.705-4.109l-410.958-410.951c-6.234-6.239-16.354-6.239-22.61 0l-410.95 410.953c-1.279 1.277-1.172 3.107-1.916 4.641-11.522 7.794-19.571 20.334-19.571 35.282z",
"M548.010667 233.088c-15.658667-24.576-56.32-24.576-72.021334 0l-298.666666 469.333333a42.794667 42.794667 0 0 0-1.408 43.477334c7.509333 13.610667 21.845333 22.101333 37.418666 22.101333h597.333334a42.709333 42.709333 0 0 0 36.010666-65.621333l-298.666666-469.290667zM291.029333 682.666667L512 335.488 732.970667 682.666667H291.029333z",
"M512.1 511.2m-447.3 0a447.3 447.3 0 1 0 894.6 0 447.3 447.3 0 1 0-894.6 0Z",
};
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Media;
namespace AIStudio.Wpf.DiagramDesigner
{
public class StrokeDashArray
{
public static readonly List<DoubleCollection> Dash = new List<DoubleCollection>
{
new DoubleCollection() { 1, 0 },
new DoubleCollection() { 8, 4 },
new DoubleCollection() { 1, 4 },
new DoubleCollection() { 8, 4, 2, 4 },
new DoubleCollection() { 8, 4, 2, 4, 2, 4 },
new DoubleCollection() { 8, 4, 8, 4, 2, 4 },
new DoubleCollection() { 18, 4, 4, 4 },
new DoubleCollection() { 18, 4, 4, 4, 4, 4 },
new DoubleCollection() { 4, 4 },
new DoubleCollection() { 2, 2 },
new DoubleCollection() { 5, 2, 2, 2 },
new DoubleCollection() { 5, 2, 2, 2, 2, 2 },
new DoubleCollection() { 10, 4, 4, 4 },
new DoubleCollection() { 10, 4, 4, 4, 4, 4 },
new DoubleCollection() { 16, 8 },
new DoubleCollection() { 2, 8 },
new DoubleCollection() { 16, 8, 2, 8 },
new DoubleCollection() { 16, 8, 2, 8, 2, 8 },
new DoubleCollection() { 16, 8, 16, 8, 2, 8 },
new DoubleCollection() { 40, 8, 8, 8 },
new DoubleCollection() { 40, 8, 8, 8, 8, 8 },
new DoubleCollection() { 4, 2 },
};
}
}

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", "AIStudio.Wpf.DiagramDesigner")]
[assembly: XmlnsDefinition("https://astudio.github.io/diagram", "AIStudio.Wpf.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:AIStudio.Wpf.DiagramDesigner"
xmlns:c="clr-namespace:AIStudio.Wpf.DiagramDesigner.Controls">
<!-- Connector Style -->
<Style TargetType="{x:Type s:Connector}">
<Setter Property="Width"
Value="8" />
<Setter Property="Height"
Value="8" />
<Setter Property="Cursor"
Value="Cross" />
<Setter Property="SnapsToDevicePixels"
Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type s:Connector}">
<Grid>
<!-- transparent extra space makes connector easier to hit -->
<Rectangle Fill="Transparent"
Margin="-2" />
<Rectangle Fill="Lavender"
StrokeThickness="1"
Stroke="#AA000080" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ConnectorDecoratorTemplate Default Template -->
<ControlTemplate x:Key="ConnectorDecoratorTemplate"
TargetType="{x:Type Control}">
<Grid Margin="-5">
<s:Connector x:Name="Left"
Orientation="Left"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<s:Connector x:Name="Top"
Orientation="Top"
VerticalAlignment="Top"
HorizontalAlignment="Center" />
<s:Connector x:Name="Right"
Orientation="Right"
VerticalAlignment="Center"
HorizontalAlignment="Right" />
<s:Connector x:Name="Bottom"
Orientation="Bottom"
VerticalAlignment="Bottom"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
<!-- DragThumb Default Template -->
<Style TargetType="{x:Type c:DragThumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type c:DragThumb}">
<Rectangle Fill="Transparent" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

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:AIStudio.Wpf.DiagramDesigner">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Shared.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type s:ZoomBox}">
<Style.Resources>
<VisualBrush x:Key="AlphaBrush"
Stretch="None"
TileMode="Tile"
ViewportUnits="Absolute"
Viewport="0,0,8,8">
<VisualBrush.Visual>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4" />
<ColumnDefinition Width="4" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="4" />
<RowDefinition Height="4" />
</Grid.RowDefinitions>
<Rectangle Fill="#EEE"
Grid.Row="0"
Grid.Column="0" />
<Rectangle Fill="#AAA"
Grid.Row="0"
Grid.Column="1" />
<Rectangle Fill="#AAA"
Grid.Row="1"
Grid.Column="0" />
<Rectangle Fill="#EEE"
Grid.Row="1"
Grid.Column="1" />
</Grid>
</VisualBrush.Visual>
</VisualBrush>
<Style x:Key="ToggleButtonStyle"
TargetType="ToggleButton">
<Setter Property="SnapsToDevicePixels"
Value="true" />
<Setter Property="OverridesDefaultStyle"
Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="Border"
Background="{StaticResource NormalBrush}">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="true">
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource DarkBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="Expander">
<Setter Property="SnapsToDevicePixels"
Value="true" />
<Setter Property="OverridesDefaultStyle"
Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Expander">
<DockPanel>
<ToggleButton Style="{StaticResource ToggleButtonStyle}"
DockPanel.Dock="Top"
IsChecked="{Binding Path=IsExpanded,Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalContentAlignment="Left"
VerticalContentAlignment="Center">
<ToggleButton.Content>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Path Grid.Column="0"
SnapsToDevicePixels="True"
Name="Arrow"
Fill="{TemplateBinding Foreground}"
Stroke="{TemplateBinding Foreground}"
StrokeThickness="0.5"
RenderTransformOrigin="0.5,0.5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 0 8 L 5 4 Z">
<Path.RenderTransform>
<RotateTransform Angle="0" />
</Path.RenderTransform>
</Path>
<ContentPresenter Grid.Column="1"
Name="HeaderContent"
ContentSource="Header" />
</Grid>
</ToggleButton.Content>
</ToggleButton>
<Border Name="Content">
<Border.LayoutTransform>
<ScaleTransform ScaleY="0" />
</Border.LayoutTransform>
<ContentPresenter Content="{TemplateBinding Content}" />
</Border>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="Expander.IsExpanded"
Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Content"
Storyboard.TargetProperty="LayoutTransform.ScaleY"
To="1"
Duration="0:0:0.3" />
<DoubleAnimation Storyboard.TargetName="Content"
Storyboard.TargetProperty="Opacity"
To="1"
Duration="0:0:0.3" />
<DoubleAnimation Storyboard.TargetName="Arrow"
Storyboard.TargetProperty="(FrameworkElement.RenderTransform).(RotateTransform.Angle)"
Duration="0:0:0.2"
To="90"
DecelerationRatio="1" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Content"
Storyboard.TargetProperty="LayoutTransform.ScaleY"
To="0"
Duration="0:0:0.3" />
<DoubleAnimation Storyboard.TargetName="Content"
Storyboard.TargetProperty="Opacity"
To="0"
Duration="0:0:0.3" />
<DoubleAnimation Storyboard.TargetName="Arrow"
Storyboard.TargetProperty="(FrameworkElement.RenderTransform).(RotateTransform.Angle)"
Duration="0:0:0.2"
AccelerationRatio="1" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="SnapsToDevicePixels"
Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type s:ZoomBox}">
<Border CornerRadius="1"
BorderThickness="1"
Background="#EEE"
BorderBrush="DimGray">
<Expander IsExpanded="True"
Background="Transparent">
<Border BorderBrush="DimGray"
BorderThickness="0,1,0,0"
Padding="0"
Height="180">
<Grid>
<Canvas Margin="5"
Name="PART_ZoomCanvas">
<Canvas.Background>
<VisualBrush Stretch="Uniform"
Visual="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ScrollViewer.Content}" />
</Canvas.Background>
<Thumb Name="PART_ZoomThumb"
Cursor="SizeAll">
<Thumb.Style>
<Style TargetType="Thumb">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Rectangle StrokeThickness="1"
Stroke="Black"
Fill="Transparent" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Thumb.Style>
</Thumb>
</Canvas>
</Grid>
</Border>
<Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Slider Name="PART_ZoomSlider"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="0"
Ticks="25,50,75,100,125,150,200,300,400,500"
Minimum="25"
Maximum="500"
SmallChange="25"
LargeChange="25"
Value="100"
MinWidth="104"
MinHeight="21"
IsSnapToTickEnabled="True"
IsMoveToPointEnabled="False" />
<TextBlock Text="{Binding ElementName=PART_ZoomSlider, Path=Value}"
Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Margin="0,0,14,0" />
<TextBlock Text="%"
Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Margin="1,0,2,0" />
</Grid>
</Expander.Header>
</Expander>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

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 AIStudio.Wpf.DiagramDesigner
{
public class DesignerItemsControlItemStyleSelector : StyleSelector
{
static DesignerItemsControlItemStyleSelector()
{
Instance = new DesignerItemsControlItemStyleSelector();
}
public static DesignerItemsControlItemStyleSelector Instance
{
get;
private set;
}
public override Style SelectStyle(object item, DependencyObject container)
{
ItemsControl itemsControl = ItemsControl.ItemsControlFromItemContainer(container);
if (itemsControl == null)
throw new InvalidOperationException("DesignerItemsControlItemStyleSelector : Could not find ItemsControl");
if (item is GifImageItemViewModel)
{
return (Style)itemsControl.FindResource("gifimageItemStyle");
}
if (item is LinkPointDesignerItemViewModel)
{
return (Style)itemsControl.FindResource("linkpointItemStyle");
}
if (item is PointDesignerItemViewModel)
{
return (Style)itemsControl.FindResource("pointItemStyle");
}
if (item is LogicalGateItemViewModelBase)
{
return (Style)itemsControl.FindResource("logicalItemStyle");
}
if (item is DesignerItemViewModelBase)
{
return (Style)itemsControl.FindResource("designerItemStyle");
}
if (item is ConnectorViewModel)
{
return (Style)itemsControl.FindResource("connectorItemStyle");
}
return null;
}
}
}

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:AIStudio.Wpf.DiagramDesigner"
xmlns:c="clr-namespace:AIStudio.Wpf.DiagramDesigner.Controls"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:gif="http://wpfanimatedgif.codeplex.com" >
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<s:ColorBrushConverter x:Key="ColorBrushConverter" />
<s:ConectorOrientationConverter x:Key="ConectorOrientationConverter" />
<s:ConectorValueConverter x:Key="ConectorValueConverter"/>
<s:ArrowPathConverter x:Key="ArrowPathConverter"/>
<s:ArrowSizeConverter x:Key="ArrowSizeConverter"/>
<s:LineDashConverter x:Key="LineDashConverter"/>
<s:ClipConverter x:Key="ClipConverter"/>
<DataTemplate DataType="{x:Type s:TextDesignerItemViewModel}">
<Grid >
<Border Background="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}" IsHitTestVisible="False"/>
<Grid Margin="5">
<s:TextControl s:ControlAttachProperty.Watermark="{Binding Watermark}" />
</Grid>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type s:ShapeDesignerItemViewModel}">
<Grid IsHitTestVisible="False" Background="White">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="显示点" IsCheckable="True" IsChecked="{Binding ShowConnectors}" />
</ContextMenu>
</Grid.ContextMenu>
<Control x:Name="control" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding DrawMode}" Value="Line">
<Setter TargetName="control" Property="Template">
<Setter.Value>
<ControlTemplate>
<Line X1="{Binding ConnectionPoints[0].X}" Y1="{Binding ConnectionPoints[0].Y}"
X2="{Binding ConnectionPoints[1].X}" Y2="{Binding ConnectionPoints[1].Y}"
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
StrokeThickness="{Binding ColorViewModel.LineWidth}"
Stretch="Fill"></Line>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding DrawMode}" Value="Rectangle">
<Setter TargetName="control" Property="Template">
<Setter.Value>
<ControlTemplate>
<Rectangle
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
StrokeThickness="{Binding ColorViewModel.LineWidth}"
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
Stretch="Fill"></Rectangle>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding DrawMode}" Value="Ellipse">
<Setter TargetName="control" Property="Template">
<Setter.Value>
<ControlTemplate>
<Ellipse
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
StrokeThickness="{Binding ColorViewModel.LineWidth}"
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
Stretch="Fill"></Ellipse>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding DrawMode}" Value="Polyline">
<Setter TargetName="control" Property="Template">
<Setter.Value>
<ControlTemplate>
<Polyline
Points="{Binding ConnectionPoints, Converter={x:Static s:ConnectionPathConverter.Instance}}"
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
StrokeThickness="{Binding ColorViewModel.LineWidth}"
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
FillRule="Nonzero"
Stretch="Fill"></Polyline>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding DrawMode}" Value="Polygon">
<Setter TargetName="control" Property="Template">
<Setter.Value>
<ControlTemplate>
<Polygon
Points="{Binding ConnectionPoints, Converter={x:Static s:ConnectionPathConverter.Instance}}"
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
StrokeThickness="{Binding ColorViewModel.LineWidth}"
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
FillRule="Nonzero"
Stretch="Fill"></Polygon>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding DrawMode}" Value="DirectLine">
<Setter TargetName="control" Property="Template">
<Setter.Value>
<ControlTemplate>
<Polyline
Points="{Binding ConnectionPoints, Converter={x:Static s:ConnectionPathConverter.Instance}}"
Stroke="{Binding ColorViewModel.LineColor,Converter={StaticResource ColorBrushConverter}}"
StrokeThickness="{Binding ColorViewModel.LineWidth}"
Fill="{Binding ColorViewModel.FillColor,Converter={StaticResource ColorBrushConverter}}"
FillRule="Nonzero"
Stretch="Fill"></Polyline>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate DataType="{x:Type s:GroupDesignerItemViewModel}">
<Grid IsHitTestVisible="{Binding IsHitTestVisible}">
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type s:GifImageItemViewModel}">
<Grid IsHitTestVisible="False">
<Image Name="PART_Image_run" gif:ImageBehavior.AnimatedSource="{Binding Icon}" gif:ImageBehavior.AutoStart="True" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Visible"/>
<Control x:Name="control" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsRunning}" Value="false">
<Setter TargetName="PART_Image_run" Property="gif:ImageBehavior.AutoStart" Value="False" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate DataType="{x:Type s:VideoItemViewModel}">
<Grid IsHitTestVisible="False">
<MediaElement x:Name="MediaPlayer" LoadedBehavior="Play" Source="{Binding Icon}" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Visible"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type s:ImageItemViewModel}">
<Grid ToolTip="{Binding Icon}">
<Grid IsHitTestVisible="False" ClipToBounds="True">
<Image x:Name="image" Source="{Binding Icon}" Stretch="Fill"
Margin="{Binding Object,Converter={StaticResource ClipConverter},ConverterParameter='Margin'}"
Clip="{Binding Object,Converter={StaticResource ClipConverter},ConverterParameter='Clip'}">
</Image>
<Image x:Name="gif" gif:ImageBehavior.AnimatedSource="{Binding Icon}" gif:ImageBehavior.AutoStart="True" Visibility="Collapsed" Stretch="Fill"/>
</Grid>
<!-- PART_ResizeDecorator -->
<Border x:Name="PART_ResizeDecorator" SnapsToDevicePixels="true" Margin="{Binding ResizeMargin,Mode=TwoWay}" Visibility="Collapsed">
<Grid x:Name="Grid" Margin="-2">
<c:BorderResizeThumb Height="5" Cursor="SizeAll" Margin="-3" ResizeMode="DragMargin" BorderBrush="Blue" BorderThickness="5" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<c:BorderResizeThumb Width="5" Cursor="SizeAll" Margin="-3" ResizeMode="DragMargin" BorderBrush="Blue" BorderThickness="5" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Stretch" HorizontalAlignment="Left"/>
<c:BorderResizeThumb Width="5" Cursor="SizeAll" Margin="-3" ResizeMode="DragMargin" BorderBrush="Blue" BorderThickness="5" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
<c:BorderResizeThumb Height="5" Cursor="SizeAll" Margin="-3" ResizeMode="DragMargin" BorderBrush="Blue" BorderThickness="5" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Bottom" HorizontalAlignment="Stretch"/>
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNS" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Top" HorizontalAlignment="Center"/>
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeWE" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Center" HorizontalAlignment="Left"/>
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeWE" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Center" HorizontalAlignment="Right"/>
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNS" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNWSE" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Top" HorizontalAlignment="Left"/>
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNESW" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Top" HorizontalAlignment="Right"/>
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNESW" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
<c:BorderResizeThumb Width="5" Height="5" Cursor="SizeNWSE" ResizeMode="Margin" Margin="-3" ResizeElement="{Binding ElementName=PART_ResizeDecorator}"
VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Grid>
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Suffix}" Value=".gif">
<Setter TargetName="gif" Property="Visibility" Value="Visible"/>
<Setter TargetName="image" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding ResizeMode}" Value="True">
<Setter TargetName="PART_ResizeDecorator" Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding Suffix}" Value=".txt">
<Setter TargetName="image" Property="Source" Value="pack://application:,,,/AIStudio.Wpf.DiagramDesigner;component/Images/file.png"/>
<Setter TargetName="image" Property="Margin" Value="0"/>
<Setter TargetName="image" Property="Clip" Value="{x:Null}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>

View File

@@ -0,0 +1,14 @@
<ItemsControl x:Class="AIStudio.Wpf.DiagramDesigner.ConnectorContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:s="clr-namespace:AIStudio.Wpf.DiagramDesigner"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas x:Name="rootCanvas" Loaded="rootCanvas_Loaded"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

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 AIStudio.Wpf.DiagramDesigner
{
/// <summary>
/// Interaction logic for ConnectorContainer.xaml
/// </summary>
public partial class ConnectorContainer : ItemsControl
{
private Canvas rootCanvas;
public ConnectorContainer()
{
InitializeComponent();
((INotifyCollectionChanged)Items).CollectionChanged += ConnectorContainer_CollectionChanged;
}
void ConnectorContainer_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach(var item in e.NewItems)
{
FullyCreatedConnectorInfo vm = item as FullyCreatedConnectorInfo;
var connector = ItemContainerGenerator.ContainerFromItem(item) as ContentPresenter;
Canvas.SetLeft(connector, vm.DataItem.ItemWidth * vm.XRatio - vm.ConnectorWidth / 2);
Canvas.SetTop(connector, vm.DataItem.ItemHeight * vm.YRatio - vm.ConnectorHeight / 2);
}
//SetConnectorLocation();
}
}
void ConnectorContainer_SizeChanged(object sender, SizeChangedEventArgs e)
{
SetConnectorLocation();
}
private void rootCanvas_Loaded(object sender, RoutedEventArgs e)
{
rootCanvas = sender as Canvas;
SetConnectorLocation();
SizeChanged += ConnectorContainer_SizeChanged;
}
private void SetConnectorLocation()
{
foreach (var connector in rootCanvas.Children.OfType<ContentPresenter>())
{
var vm = connector.DataContext as FullyCreatedConnectorInfo;
if (vm != null)
{
Canvas.SetLeft(connector, vm.DataItem.ItemWidth * vm.XRatio - vm.ConnectorWidth / 2);
Canvas.SetTop(connector, vm.DataItem.ItemHeight * vm.YRatio - vm.ConnectorHeight / 2);
}
}
}
}
}

File diff suppressed because it is too large Load Diff

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