Refactor how data context is handled

This commit is contained in:
Wiesław Šoltés 2024-09-28 23:22:41 +02:00
Родитель d15749f724
Коммит 16bfdd230d
31 изменённых файлов: 268 добавлений и 388 удалений

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

@ -201,10 +201,12 @@ public partial class MainViewViewModel : ViewModelBase
{
var control = new DrawingNode
{
DataContext = Editor.Drawing
DrawingSource = Editor.Drawing,
Width = Editor.Drawing.Width,
Height = Editor.Drawing.Height,
};
var root = new ExportRoot()
var root = new ExportRoot
{
Width = Editor.Drawing.Width,
Height = Editor.Drawing.Height,

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

@ -75,7 +75,6 @@
</UserControl.KeyBindings>
<DockPanel>
<views:MenuView ZoomControl="{Binding #EditorControl.ZoomControl}"
DrawingNode="{Binding #EditorControl.DrawingNode}"
x:CompileBindings="False"
DockPanel.Dock="Top" />
<Separator IsVisible="False" Classes="horizontal" DockPanel.Dock="Top" />
@ -92,23 +91,12 @@
IsVisible="{Binding IsToolboxVisible}">
<Separator Classes="vertical" DockPanel.Dock="Right" />
<editor:Toolbox TemplatesSource="{Binding Editor.Templates}"
Drawing="{Binding Editor.Drawing}"
Name="ToolboxView" />
</DockPanel>
<ThemeVariantScope RequestedThemeVariant="Light"
Grid.Column="1" Grid.ColumnSpan="2">
<editor:Editor Name="EditorControl"
DataContext="{Binding Editor.Drawing, FallbackValue={x:Null}}"
DrawingWidth="{Binding Width}"
DrawingHeight="{Binding Height}"
NodesSource="{Binding Nodes}"
ConnectorsSource="{Binding Connectors}"
EnableSnap="{Binding Settings.EnableSnap}"
SnapX="{Binding Settings.SnapX}"
SnapY="{Binding Settings.SnapY}"
EnableGrid="{Binding Settings.EnableGrid}"
GridCellWidth="{Binding Settings.GridCellWidth}"
GridCellHeight="{Binding Settings.GridCellHeight}"/>
DrawingSource="{Binding Editor.Drawing, FallbackValue={x:Null}}" />
</ThemeVariantScope>
<GridSplitter Grid.Column="1" Background="Transparent" />
</Grid>

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

@ -9,9 +9,6 @@ public partial class MenuView : UserControl
public static readonly StyledProperty<NodeZoomBorder?> ZoomControlProperty =
AvaloniaProperty.Register<MenuView, NodeZoomBorder?>(nameof(ZoomControl));
public static readonly StyledProperty<DrawingNode?> DrawingNodeProperty =
AvaloniaProperty.Register<MenuView, DrawingNode?>(nameof(DrawingNode));
public MenuView()
{
InitializeComponent();
@ -22,10 +19,4 @@ public partial class MenuView : UserControl
get => GetValue(ZoomControlProperty);
set => SetValue(ZoomControlProperty, value);
}
public DrawingNode? DrawingNode
{
get => GetValue(DrawingNodeProperty);
set => SetValue(DrawingNodeProperty, value);
}
}

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

@ -10,6 +10,15 @@ namespace NodeEditor.Behaviors;
public class ConnectorsSelectedBehavior : Behavior<ItemsControl>
{
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<ConnectorsSelectedBehavior, IDrawingNode?>(nameof(DrawingSource));
public IDrawingNode? DrawingSource
{
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
private IDisposable? _dataContextDisposable;
private IDrawingNode? _drawingNode;
@ -66,7 +75,7 @@ public class ConnectorsSelectedBehavior : Behavior<ItemsControl>
private void DrawingNode_SelectionChanged(object? sender, EventArgs e)
{
if (AssociatedObject?.DataContext is not IDrawingNode)
if (DrawingSource is not IDrawingNode)
{
return;
}

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

@ -9,9 +9,18 @@ namespace NodeEditor.Behaviors;
public class DrawingDropHandler : DefaultDropHandler
{
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<DrawingDropHandler, IDrawingNode?>(nameof(DrawingSource));
public static readonly StyledProperty<Control?> RelativeToProperty =
AvaloniaProperty.Register<DrawingDropHandler, Control?>(nameof(RelativeTo));
public IDrawingNode? DrawingSource
{
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
public Control? RelativeTo
{
get => GetValue(RelativeToProperty);
@ -27,9 +36,9 @@ public class DrawingDropHandler : DefaultDropHandler
}
var point = GetPosition(relativeTo, e);
if (relativeTo is DrawingNode drawingNode)
if (relativeTo is DrawingNode { DrawingSource: not null } drawingNode)
{
point = SnapHelper.Snap(point, drawingNode.SnapX, drawingNode.SnapY, drawingNode.EnableSnap);
point = SnapHelper.Snap(point, drawingNode.DrawingSource.Settings.SnapX, drawingNode.DrawingSource.Settings.SnapY, drawingNode.DrawingSource.Settings.EnableSnap);
}
if (e.Data.Contains(DataFormats.Text))

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

@ -1,4 +1,5 @@
using Avalonia.Controls;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Xaml.Interactivity;
@ -8,6 +9,15 @@ namespace NodeEditor.Behaviors;
public class DrawingMovedBehavior : Behavior<ItemsControl>
{
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<DrawingMovedBehavior, IDrawingNode?>(nameof(DrawingSource));
public IDrawingNode? DrawingSource
{
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
@ -30,7 +40,7 @@ public class DrawingMovedBehavior : Behavior<ItemsControl>
private void Moved(object? sender, PointerEventArgs e)
{
if (AssociatedObject?.DataContext is not IDrawingNode drawingNode)
if (DrawingSource is not IDrawingNode drawingNode)
{
return;
}

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

@ -1,4 +1,5 @@
using Avalonia.Controls;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Xaml.Interactivity;
@ -8,6 +9,15 @@ namespace NodeEditor.Behaviors;
public class DrawingPressedBehavior : Behavior<ItemsControl>
{
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<DrawingPressedBehavior, IDrawingNode?>(nameof(DrawingSource));
public IDrawingNode? DrawingSource
{
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
@ -35,7 +45,7 @@ public class DrawingPressedBehavior : Behavior<ItemsControl>
return;
}
if (AssociatedObject?.DataContext is not IDrawingNode drawingNode)
if (DrawingSource is not IDrawingNode drawingNode)
{
return;
}

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

@ -12,21 +12,15 @@ namespace NodeEditor.Behaviors;
public class DrawingSelectionBehavior : Behavior<ItemsControl>
{
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<DrawingSelectionBehavior, IDrawingNode?>(nameof(DrawingSource));
public static readonly StyledProperty<Control?> InputSourceProperty =
AvaloniaProperty.Register<DrawingSelectionBehavior, Control?>(nameof(InputSource));
public static readonly StyledProperty<Canvas?> AdornerCanvasProperty =
AvaloniaProperty.Register<DrawingSelectionBehavior, Canvas?>(nameof(AdornerCanvas));
public static readonly StyledProperty<bool> EnableSnapProperty =
AvaloniaProperty.Register<DrawingSelectionBehavior, bool>(nameof(EnableSnap));
public static readonly StyledProperty<double> SnapXProperty =
AvaloniaProperty.Register<DrawingSelectionBehavior, double>(nameof(SnapX), 1.0);
public static readonly StyledProperty<double> SnapYProperty =
AvaloniaProperty.Register<DrawingSelectionBehavior, double>(nameof(SnapY), 1.0);
private IDisposable? _dataContextDisposable;
private IDrawingNode? _drawingNode;
private SelectionAdorner? _selectionAdorner;
@ -36,6 +30,12 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
private Rect _selectedRect;
private Control? _inputSource;
public IDrawingNode? DrawingSource
{
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
public Control? InputSource
{
get => GetValue(InputSourceProperty);
@ -48,24 +48,6 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
set => SetValue(AdornerCanvasProperty, value);
}
public bool EnableSnap
{
get => GetValue(EnableSnapProperty);
set => SetValue(EnableSnapProperty, value);
}
public double SnapX
{
get => GetValue(SnapXProperty);
set => SetValue(SnapXProperty, value);
}
public double SnapY
{
get => GetValue(SnapYProperty);
set => SetValue(SnapYProperty, value);
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
@ -95,12 +77,12 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
_inputSource.AddHandler(InputElement.PointerCaptureLostEvent, CaptureLost, RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
_inputSource.AddHandler(InputElement.PointerMovedEvent, Moved, RoutingStrategies.Tunnel | RoutingStrategies.Bubble);
_dataContextDisposable = AssociatedObject
.GetObservable(StyledElement.DataContextProperty)
.Subscribe(new AnonymousObserver<object?>(
_dataContextDisposable = this
.GetObservable(DrawingSourceProperty)
.Subscribe(new AnonymousObserver<IDrawingNode?>(
x =>
{
if (x is IDrawingNode drawingNode)
if (x is { } drawingNode)
{
if (_drawingNode == drawingNode)
{
@ -163,7 +145,7 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
private void DrawingNode_SelectionChanged(object? sender, EventArgs e)
{
if (AssociatedObject?.DataContext is not IDrawingNode)
if (DrawingSource is null)
{
return;
}
@ -175,7 +157,7 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
if (selectedNodes is { Count: > 0 } || selectedConnectors is { Count: > 0 })
{
_selectedRect = HitTestHelper.CalculateSelectedRect(AssociatedObject);
_selectedRect = HitTestHelper.CalculateSelectedRect(_drawingNode, AssociatedObject);
if (_selectedAdorner is not null)
{
@ -203,7 +185,7 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
var info = e.GetCurrentPoint(_inputSource);
if (AssociatedObject?.DataContext is not IDrawingNode drawingNode)
if (DrawingSource is not { } drawingNode)
{
return;
}
@ -236,11 +218,11 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
if (_selectedRect.Contains(position))
{
_dragSelectedItems = true;
_start = SnapHelper.Snap(position, SnapX, SnapY, EnableSnap);
_start = SnapHelper.Snap(position, drawingNode.Settings.SnapX, drawingNode.Settings.SnapY, drawingNode.Settings.EnableSnap);
}
else
{
HitTestHelper.FindSelectedNodes(AssociatedObject, pointerHitTestRect);
HitTestHelper.FindSelectedNodes(drawingNode, AssociatedObject, pointerHitTestRect);
selectedNodes = drawingNode.GetSelectedNodes();
selectedConnectors = drawingNode.GetSelectedConnectors();
@ -248,7 +230,7 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
if (selectedNodes is { Count: > 0 } || selectedConnectors is { Count: > 0 })
{
_dragSelectedItems = true;
_start = SnapHelper.Snap(position, SnapX, SnapY, EnableSnap);
_start = SnapHelper.Snap(position, drawingNode.Settings.SnapX, drawingNode.Settings.SnapY, drawingNode.Settings.EnableSnap);
}
else
{
@ -264,7 +246,7 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
}
else
{
HitTestHelper.FindSelectedNodes(AssociatedObject, pointerHitTestRect);
HitTestHelper.FindSelectedNodes(drawingNode, AssociatedObject, pointerHitTestRect);
selectedNodes = drawingNode.GetSelectedNodes();
selectedConnectors = drawingNode.GetSelectedConnectors();
@ -272,7 +254,7 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
if (selectedNodes is { Count: > 0 } || selectedConnectors is { Count: > 0 })
{
_dragSelectedItems = true;
_start = SnapHelper.Snap(position, SnapX, SnapY, EnableSnap);
_start = SnapHelper.Snap(position, drawingNode.Settings.SnapX, drawingNode.Settings.SnapY, drawingNode.Settings.EnableSnap);
}
}
@ -284,7 +266,7 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
RemoveSelected();
if (e.Source is not Control { DataContext: not IDrawingNode })
// TODO: if (e.Source is not Control { DataContext: not IDrawingNode })
{
AddSelection(position.X, position.Y);
}
@ -298,15 +280,15 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
{
if (Equals(e.Pointer.Captured, _inputSource))
{
if (e.InitialPressMouseButton == MouseButton.Left && AssociatedObject?.DataContext is IDrawingNode)
if (e.InitialPressMouseButton == MouseButton.Left && DrawingSource is IDrawingNode drawingNode)
{
_dragSelectedItems = false;
if (e.Source is not Control { DataContext: not IDrawingNode })
// TODO: if (e.Source is not Control { DataContext: not IDrawingNode })
{
if (_selectionAdorner is not null)
{
HitTestHelper.FindSelectedNodes(AssociatedObject, _selectionAdorner.GetRect());
HitTestHelper.FindSelectedNodes(drawingNode, AssociatedObject, _selectionAdorner.GetRect());
}
RemoveSelection();
@ -326,19 +308,19 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
{
var info = e.GetCurrentPoint(_inputSource);
if (Equals(e.Pointer.Captured, _inputSource) && info.Properties.IsLeftButtonPressed && AssociatedObject?.DataContext is IDrawingNode)
if (Equals(e.Pointer.Captured, _inputSource) && info.Properties.IsLeftButtonPressed && DrawingSource is IDrawingNode)
{
var position = e.GetPosition(AssociatedObject);
if (_dragSelectedItems)
{
if (AssociatedObject?.DataContext is IDrawingNode drawingNode)
if (DrawingSource is IDrawingNode drawingNode)
{
var selectedNodes = drawingNode.GetSelectedNodes();
if (selectedNodes is { Count: > 0 } && drawingNode.Nodes is { Count: > 0 })
{
position = SnapHelper.Snap(position, SnapX, SnapY, EnableSnap);
position = SnapHelper.Snap(position, drawingNode.Settings.SnapX, drawingNode.Settings.SnapY, drawingNode.Settings.EnableSnap);
var deltaX = position.X - _start.X;
var deltaY = position.Y - _start.Y;
@ -353,7 +335,7 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
}
}
var selectedRect = HitTestHelper.CalculateSelectedRect(AssociatedObject);
var selectedRect = HitTestHelper.CalculateSelectedRect(drawingNode, AssociatedObject);
_selectedRect = selectedRect;
@ -365,7 +347,7 @@ public class DrawingSelectionBehavior : Behavior<ItemsControl>
}
else
{
if (e.Source is not Control { DataContext: not IDrawingNode })
// TODO: if (e.Source is not Control { DataContext: not IDrawingNode })
{
UpdateSelection(position.X, position.Y);

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

@ -8,13 +8,13 @@ namespace NodeEditor.Behaviors;
public class InsertTemplateOnDoubleTappedBehavior : Behavior<ListBoxItem>
{
public static readonly StyledProperty<IDrawingNode?> DrawingProperty =
AvaloniaProperty.Register<InsertTemplateOnDoubleTappedBehavior, IDrawingNode?>(nameof(Drawing));
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<InsertTemplateOnDoubleTappedBehavior, IDrawingNode?>(nameof(DrawingSource));
public IDrawingNode? Drawing
public IDrawingNode? DrawingSource
{
get => GetValue(DrawingProperty);
set => SetValue(DrawingProperty, value);
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
protected override void OnAttached()
@ -37,7 +37,7 @@ public class InsertTemplateOnDoubleTappedBehavior : Behavior<ListBoxItem>
private void DoubleTapped(object? sender, RoutedEventArgs args)
{
if (AssociatedObject is { DataContext: INodeTemplate template } && Drawing is { } drawing)
if (AssociatedObject is { DataContext: INodeTemplate template } && DrawingSource is { } drawing)
{
var node = drawing.Clone(template.Template);
if (node is not null)

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

@ -11,6 +11,15 @@ namespace NodeEditor.Behaviors;
public class NodesSelectedBehavior : Behavior<ItemsControl>
{
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<NodesSelectedBehavior, IDrawingNode?>(nameof(DrawingSource));
public IDrawingNode? DrawingSource
{
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
private IDisposable? _dataContextDisposable;
private IDrawingNode? _drawingNode;
@ -66,7 +75,7 @@ public class NodesSelectedBehavior : Behavior<ItemsControl>
private void DrawingNode_SelectionChanged(object? sender, EventArgs e)
{
if (AssociatedObject?.DataContext is not IDrawingNode)
if (DrawingSource is not IDrawingNode)
{
return;
}

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

@ -1,14 +1,23 @@
using Avalonia.Controls.Presenters;
using Avalonia;
using Avalonia.Controls.Presenters;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Xaml.Interactivity;
using NodeEditor.Controls;
using NodeEditor.Model;
namespace NodeEditor.Behaviors;
public class PinPressedBehavior : Behavior<ContentPresenter>
{
public static readonly StyledProperty<IPin?> PinSourceProperty =
AvaloniaProperty.Register<PinPressedBehavior, IPin?>(nameof(PinSource));
public IPin? PinSource
{
get => GetValue(PinSourceProperty);
set => SetValue(PinSourceProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();

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

@ -9,6 +9,9 @@ namespace NodeEditor.Controls;
[PseudoClasses(":selected")]
public class Connector : Shape
{
public static readonly StyledProperty<IConnector?> ConnectorSourceProperty =
AvaloniaProperty.Register<Connector, IConnector?>(nameof(ConnectorSource));
public static readonly StyledProperty<Point> StartPointProperty =
AvaloniaProperty.Register<Connector, Point>(nameof(StartPoint));
@ -31,6 +34,12 @@ public class Connector : Shape
OrientationProperty);
}
public IConnector? ConnectorSource
{
get => GetValue(ConnectorSourceProperty);
set => SetValue(ConnectorSourceProperty, value);
}
public Point StartPoint
{
get => GetValue(StartPointProperty);

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

@ -1,17 +1,18 @@
using System.Collections;
using Avalonia;
using Avalonia.Controls.Primitives;
using NodeEditor.Model;
namespace NodeEditor.Controls;
public class Connectors : TemplatedControl
{
public static readonly StyledProperty<IEnumerable?> ConnectorsSourceProperty =
AvaloniaProperty.Register<Connectors, IEnumerable?>(nameof(ConnectorsSource));
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<Connectors, IDrawingNode?>(nameof(DrawingSource));
public IEnumerable? ConnectorsSource
public IDrawingNode? DrawingSource
{
get => GetValue(ConnectorsSourceProperty);
set => SetValue(ConnectorsSourceProperty, value);
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
}

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

@ -1,17 +1,14 @@
using System.Collections;
using Avalonia;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using NodeEditor.Model;
namespace NodeEditor.Controls;
public class DrawingNode : TemplatedControl
{
public static readonly StyledProperty<IEnumerable?> NodesSourceProperty =
AvaloniaProperty.Register<DrawingNode, IEnumerable?>(nameof(NodesSource));
public static readonly StyledProperty<IEnumerable?> ConnectorsSourceProperty =
AvaloniaProperty.Register<DrawingNode, IEnumerable?>(nameof(ConnectorsSource));
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<DrawingNode, IDrawingNode?>(nameof(DrawingSource));
public static readonly StyledProperty<Control?> InputSourceProperty =
AvaloniaProperty.Register<DrawingNode, Control?>(nameof(InputSource));
@ -19,34 +16,10 @@ public class DrawingNode : TemplatedControl
public static readonly StyledProperty<Canvas?> AdornerCanvasProperty =
AvaloniaProperty.Register<DrawingNode, Canvas?>(nameof(AdornerCanvas));
public static readonly StyledProperty<bool> EnableSnapProperty =
AvaloniaProperty.Register<DrawingNode, bool>(nameof(EnableSnap));
public static readonly StyledProperty<double> SnapXProperty =
AvaloniaProperty.Register<DrawingNode, double>(nameof(SnapX), 1.0);
public static readonly StyledProperty<double> SnapYProperty =
AvaloniaProperty.Register<DrawingNode, double>(nameof(SnapY), 1.0);
public static readonly StyledProperty<bool> EnableGridProperty =
AvaloniaProperty.Register<DrawingNode, bool>(nameof(EnableGrid));
public static readonly StyledProperty<double> GridCellWidthProperty =
AvaloniaProperty.Register<DrawingNode, double>(nameof(GridCellWidth));
public static readonly StyledProperty<double> GridCellHeightProperty =
AvaloniaProperty.Register<DrawingNode, double>(nameof(GridCellHeight));
public IEnumerable? NodesSource
public IDrawingNode? DrawingSource
{
get => GetValue(NodesSourceProperty);
set => SetValue(NodesSourceProperty, value);
}
public IEnumerable? ConnectorsSource
{
get => GetValue(ConnectorsSourceProperty);
set => SetValue(ConnectorsSourceProperty, value);
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
public Control? InputSource
@ -60,40 +33,4 @@ public class DrawingNode : TemplatedControl
get => GetValue(AdornerCanvasProperty);
set => SetValue(AdornerCanvasProperty, value);
}
public bool EnableSnap
{
get => GetValue(EnableSnapProperty);
set => SetValue(EnableSnapProperty, value);
}
public double SnapX
{
get => GetValue(SnapXProperty);
set => SetValue(SnapXProperty, value);
}
public double SnapY
{
get => GetValue(SnapYProperty);
set => SetValue(SnapYProperty, value);
}
public bool EnableGrid
{
get => GetValue(EnableGridProperty);
set => SetValue(EnableGridProperty, value);
}
public double GridCellWidth
{
get => GetValue(GridCellWidthProperty);
set => SetValue(GridCellWidthProperty, value);
}
public double GridCellHeight
{
get => GetValue(GridCellHeightProperty);
set => SetValue(GridCellHeightProperty, value);
}
}

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

@ -4,19 +4,16 @@ using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using NodeEditor.Model;
namespace NodeEditor.Controls;
[TemplatePart("PART_ZoomBorder", typeof(NodeZoomBorder))]
[TemplatePart("PART_Drawing", typeof(DrawingNode))]
[TemplatePart("PART_AdornerCanvas", typeof(Canvas))]
public class Editor : TemplatedControl
{
public static readonly StyledProperty<IEnumerable?> NodesSourceProperty =
AvaloniaProperty.Register<Editor, IEnumerable?>(nameof(NodesSource));
public static readonly StyledProperty<IEnumerable?> ConnectorsSourceProperty =
AvaloniaProperty.Register<Editor, IEnumerable?>(nameof(ConnectorsSource));
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<Editor, IDrawingNode?>(nameof(DrawingSource));
public static readonly StyledProperty<Control?> InputSourceProperty =
AvaloniaProperty.Register<Editor, Control?>(nameof(InputSource));
@ -24,46 +21,13 @@ public class Editor : TemplatedControl
public static readonly StyledProperty<Canvas?> AdornerCanvasProperty =
AvaloniaProperty.Register<Editor, Canvas?>(nameof(AdornerCanvas));
public static readonly StyledProperty<bool> EnableSnapProperty =
AvaloniaProperty.Register<Editor, bool>(nameof(EnableSnap), false, false, BindingMode.TwoWay);
public static readonly StyledProperty<double> SnapXProperty =
AvaloniaProperty.Register<Editor, double>(nameof(SnapX), 1.0, false, BindingMode.TwoWay);
public static readonly StyledProperty<double> SnapYProperty =
AvaloniaProperty.Register<Editor, double>(nameof(SnapY), 1.0, false, BindingMode.TwoWay);
public static readonly StyledProperty<bool> EnableGridProperty =
AvaloniaProperty.Register<Editor, bool>(nameof(EnableGrid), false, false, BindingMode.TwoWay);
public static readonly StyledProperty<double> GridCellWidthProperty =
AvaloniaProperty.Register<Editor, double>(nameof(GridCellWidth), 15.0, false, BindingMode.TwoWay);
public static readonly StyledProperty<double> GridCellHeightProperty =
AvaloniaProperty.Register<Editor, double>(nameof(GridCellHeight), 15.0, false, BindingMode.TwoWay);
public static readonly StyledProperty<double> DrawingWidthProperty =
AvaloniaProperty.Register<Editor, double>(nameof(DrawingWidth), 0.0, false, BindingMode.TwoWay);
public static readonly StyledProperty<double> DrawingHeightProperty =
AvaloniaProperty.Register<Editor, double>(nameof(DrawingHeight), 0.0, false, BindingMode.TwoWay);
public static readonly StyledProperty<NodeZoomBorder?> ZoomControlProperty =
AvaloniaProperty.Register<Editor, NodeZoomBorder?>(nameof(ZoomControl));
public static readonly StyledProperty<DrawingNode?> DrawingNodeProperty =
AvaloniaProperty.Register<Editor, DrawingNode?>(nameof(DrawingNode));
public IEnumerable? NodesSource
public IDrawingNode? DrawingSource
{
get => GetValue(NodesSourceProperty);
set => SetValue(NodesSourceProperty, value);
}
public IEnumerable? ConnectorsSource
{
get => GetValue(ConnectorsSourceProperty);
set => SetValue(ConnectorsSourceProperty, value);
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
public Control? InputSource
@ -78,72 +42,17 @@ public class Editor : TemplatedControl
set => SetValue(AdornerCanvasProperty, value);
}
public bool EnableSnap
{
get => GetValue(EnableSnapProperty);
set => SetValue(EnableSnapProperty, value);
}
public double SnapX
{
get => GetValue(SnapXProperty);
set => SetValue(SnapXProperty, value);
}
public double SnapY
{
get => GetValue(SnapYProperty);
set => SetValue(SnapYProperty, value);
}
public bool EnableGrid
{
get => GetValue(EnableGridProperty);
set => SetValue(EnableGridProperty, value);
}
public double GridCellWidth
{
get => GetValue(GridCellWidthProperty);
set => SetValue(GridCellWidthProperty, value);
}
public double GridCellHeight
{
get => GetValue(GridCellHeightProperty);
set => SetValue(GridCellHeightProperty, value);
}
public double DrawingWidth
{
get => GetValue(DrawingWidthProperty);
set => SetValue(DrawingWidthProperty, value);
}
public double DrawingHeight
{
get => GetValue(DrawingHeightProperty);
set => SetValue(DrawingHeightProperty, value);
}
public NodeZoomBorder? ZoomControl
{
get => GetValue(ZoomControlProperty);
set => SetValue(ZoomControlProperty, value);
}
public DrawingNode? DrawingNode
{
get => GetValue(DrawingNodeProperty);
set => SetValue(DrawingNodeProperty, value);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
ZoomControl = e.NameScope.Find<NodeZoomBorder>("PART_ZoomBorder");
DrawingNode = e.NameScope.Find<DrawingNode>("PART_DrawingNode");
AdornerCanvas = e.NameScope.Find<Canvas>("PART_AdornerCanvas");
}
}

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

@ -2,18 +2,19 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using NodeEditor.Model;
namespace NodeEditor.Controls;
[PseudoClasses(":selected")]
public class Node : ContentControl
{
public static readonly StyledProperty<IEnumerable?> PinsSourceProperty =
AvaloniaProperty.Register<Node, IEnumerable?>(nameof(PinsSource));
public static readonly StyledProperty<INode?> NodeSourceProperty =
AvaloniaProperty.Register<Node, INode?>(nameof(NodeSource));
public IEnumerable? PinsSource
public INode? NodeSource
{
get => GetValue(PinsSourceProperty);
set => SetValue(PinsSourceProperty, value);
get => GetValue(NodeSourceProperty);
set => SetValue(NodeSourceProperty, value);
}
}

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

@ -1,17 +1,37 @@
using System.Collections;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using NodeEditor.Model;
namespace NodeEditor.Controls;
public class Nodes : TemplatedControl
{
public static readonly StyledProperty<IEnumerable?> NodesSourceProperty =
AvaloniaProperty.Register<Nodes, IEnumerable?>(nameof(NodesSource));
public static readonly StyledProperty<IDrawingNode?> DrawingSourceProperty =
AvaloniaProperty.Register<Nodes, IDrawingNode?>(nameof(DrawingSource));
public IEnumerable? NodesSource
public static readonly StyledProperty<Control?> InputSourceProperty =
AvaloniaProperty.Register<Nodes, Control?>(nameof(InputSource));
public static readonly StyledProperty<Canvas?> AdornerCanvasProperty =
AvaloniaProperty.Register<Nodes, Canvas?>(nameof(AdornerCanvas));
public IDrawingNode? DrawingSource
{
get => GetValue(NodesSourceProperty);
set => SetValue(NodesSourceProperty, value);
get => GetValue(DrawingSourceProperty);
set => SetValue(DrawingSourceProperty, value);
}
public Control? InputSource
{
get => GetValue(InputSourceProperty);
set => SetValue(InputSourceProperty, value);
}
public Canvas? AdornerCanvas
{
get => GetValue(AdornerCanvasProperty);
set => SetValue(AdornerCanvasProperty, value);
}
}

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

@ -6,12 +6,21 @@ namespace NodeEditor.Controls;
public class Pin : TemplatedControl
{
public static readonly StyledProperty<IPin?> PinSourceProperty =
AvaloniaProperty.Register<Pin, IPin?>(nameof(PinSource));
public static readonly StyledProperty<PinAlignment> AlignmentProperty =
AvaloniaProperty.Register<Pin, PinAlignment>(nameof(Alignment));
public static readonly StyledProperty<string?> IdProperty =
AvaloniaProperty.Register<Pin, string?>(nameof(Id));
public IPin? PinSource
{
get => GetValue(PinSourceProperty);
set => SetValue(PinSourceProperty, value);
}
public PinAlignment Alignment
{
get => GetValue(AlignmentProperty);

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

@ -1,17 +1,18 @@
using System.Collections;
using Avalonia;
using Avalonia.Controls.Primitives;
using NodeEditor.Model;
namespace NodeEditor.Controls;
public class Pins : TemplatedControl
{
public static readonly StyledProperty<IEnumerable?> PinsSourceProperty =
AvaloniaProperty.Register<Pins, IEnumerable?>(nameof(PinsSource));
public static readonly StyledProperty<INode?> NodeSourceProperty =
AvaloniaProperty.Register<Pins, INode?>(nameof(NodeSource));
public IEnumerable? PinsSource
public INode? NodeSource
{
get => GetValue(PinsSourceProperty);
set => SetValue(PinsSourceProperty, value);
get => GetValue(NodeSourceProperty);
set => SetValue(NodeSourceProperty, value);
}
}

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

@ -1,4 +1,5 @@
using System.Collections;
using System.Collections.Generic;
using Avalonia;
using Avalonia.Controls.Primitives;
using NodeEditor.Model;
@ -7,21 +8,12 @@ namespace NodeEditor.Controls;
public class Toolbox : TemplatedControl
{
public static readonly StyledProperty<IEnumerable?> TemplatesSourceProperty =
AvaloniaProperty.Register<Toolbox, IEnumerable?>(nameof(TemplatesSource));
public static readonly StyledProperty<IEnumerable<INodeTemplate>?> TemplatesSourceProperty =
AvaloniaProperty.Register<Toolbox, IEnumerable<INodeTemplate>?>(nameof(TemplatesSource));
public static readonly StyledProperty<IDrawingNode?> DrawingProperty =
AvaloniaProperty.Register<Toolbox, IDrawingNode?>(nameof(Drawing));
public IEnumerable? TemplatesSource
public IEnumerable<INodeTemplate>? TemplatesSource
{
get => GetValue(TemplatesSourceProperty);
set => SetValue(TemplatesSourceProperty, value);
}
public IDrawingNode? Drawing
{
get => GetValue(DrawingProperty);
set => SetValue(DrawingProperty, value);
}
}

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

@ -167,13 +167,8 @@ internal static class HitTestHelper
new Point(bottomRightX, bottomRightY));
}
public static void FindSelectedNodes(ItemsControl? itemsControl, Rect rect)
public static void FindSelectedNodes(IDrawingNode drawingNode, ItemsControl? itemsControl, Rect rect)
{
if (itemsControl?.DataContext is not IDrawingNode drawingNode)
{
return;
}
drawingNode.NotifyDeselectedNodes();
drawingNode.NotifyDeselectedConnectors();
drawingNode.SetSelectedNodes(null);
@ -245,13 +240,8 @@ internal static class HitTestHelper
}
}
public static Rect CalculateSelectedRect(ItemsControl? itemsControl)
public static Rect CalculateSelectedRect(IDrawingNode drawingNode, ItemsControl? itemsControl)
{
if (itemsControl?.DataContext is not IDrawingNode drawingNode)
{
return default;
}
var selectedRect = new Rect();
itemsControl.UpdateLayout();

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

@ -11,7 +11,7 @@
<Setter Property="StrokeThickness" Value="2" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="ContextFlyout">
<Setter Property="ContextFlyout" x:DataType="controls:Connector">
<Setter.Value>
<Flyout>
<DockPanel>
@ -19,19 +19,19 @@
<Label Content="Orientation:" DockPanel.Dock="Top" />
<RadioButton Content="Auto"
GroupName="Orientation"
IsChecked="{Binding $parent[controls:Connector].Orientation, Converter={x:Static converters:EnumToCheckedConverter.Instance}, ConverterParameter={x:Static m:ConnectorOrientation.Auto}}"
IsChecked="{Binding Orientation, Converter={x:Static converters:EnumToCheckedConverter.Instance}, ConverterParameter={x:Static m:ConnectorOrientation.Auto}}"
DockPanel.Dock="Top" />
<RadioButton Content="Horizontal"
GroupName="Orientation"
IsChecked="{Binding $parent[controls:Connector].Orientation, Converter={x:Static converters:EnumToCheckedConverter.Instance}, ConverterParameter={x:Static m:ConnectorOrientation.Horizontal}}"
IsChecked="{Binding Orientation, Converter={x:Static converters:EnumToCheckedConverter.Instance}, ConverterParameter={x:Static m:ConnectorOrientation.Horizontal}}"
DockPanel.Dock="Top" />
<RadioButton Content="Vertical"
GroupName="Orientation"
IsChecked="{Binding $parent[controls:Connector].Orientation, Converter={x:Static converters:EnumToCheckedConverter.Instance}, ConverterParameter={x:Static m:ConnectorOrientation.Vertical}}"
IsChecked="{Binding Orientation, Converter={x:Static converters:EnumToCheckedConverter.Instance}, ConverterParameter={x:Static m:ConnectorOrientation.Vertical}}"
DockPanel.Dock="Top" />
</DockPanel>
<Label Content="Offset:" DockPanel.Dock="Top" />
<TextBox Text="{Binding $parent[controls:Connector].Offset}" DockPanel.Dock="Top" />
<TextBox Text="{Binding Offset}" DockPanel.Dock="Top" />
</DockPanel>
</Flyout>
</Setter.Value>

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

@ -12,9 +12,9 @@
<Setter Property="Template">
<ControlTemplate>
<ItemsControl x:Name="PART_ConnectorsItemsControl"
ItemsSource="{TemplateBinding ConnectorsSource}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
ItemsSource="{Binding DrawingSource.Connectors, RelativeSource={RelativeSource TemplatedParent}}"
Width="{Binding Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding Height, RelativeSource={RelativeSource TemplatedParent}}"
Background="Transparent"
IsHitTestVisible="False"
ClipToBounds="False">
@ -29,7 +29,8 @@
StartPoint="{Binding Start, Converter={x:Static converters:PinToPointConverter.Instance}}"
EndPoint="{Binding End, Converter={x:Static converters:PinToPointConverter.Instance}}"
Offset="{Binding Offset}"
Orientation="{Binding Orientation}" />
Orientation="{Binding Orientation}"
ConnectorSource="{Binding .}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

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

@ -12,17 +12,19 @@
<ControlTemplate>
<Panel x:Name="PART_Panel"
Background="{TemplateBinding Background}">
<controls:GridDecorator EnableGrid="{TemplateBinding EnableGrid}"
GridCellWidth="{TemplateBinding GridCellWidth}"
GridCellHeight="{TemplateBinding GridCellHeight}" />
<controls:GridDecorator EnableGrid="{Binding DrawingSource.Settings.EnableGrid, RelativeSource={RelativeSource TemplatedParent}}"
GridCellWidth="{Binding DrawingSource.Settings.GridCellWidth, RelativeSource={RelativeSource TemplatedParent}}"
GridCellHeight="{Binding DrawingSource.Settings.GridCellHeight, RelativeSource={RelativeSource TemplatedParent}}" />
<controls:Connectors x:Name="PART_Connectors"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
ConnectorsSource="{TemplateBinding ConnectorsSource}" />
Width="{Binding DrawingSource.Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding DrawingSource.Height, RelativeSource={RelativeSource TemplatedParent}}"
DrawingSource="{Binding DrawingSource, RelativeSource={RelativeSource TemplatedParent}}" />
<controls:Nodes x:Name="PART_Nodes"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
NodesSource="{TemplateBinding NodesSource}" />
Width="{Binding DrawingSource.Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding DrawingSource.Height, RelativeSource={RelativeSource TemplatedParent}}"
DrawingSource="{Binding DrawingSource, RelativeSource={RelativeSource TemplatedParent}}"
InputSource="{Binding InputSource, RelativeSource={RelativeSource TemplatedParent}}"
AdornerCanvas="{Binding AdornerCanvas, RelativeSource={RelativeSource TemplatedParent}}" />
</Panel>
</ControlTemplate>
</Setter>

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

@ -12,7 +12,7 @@
<DockPanel>
<!-- Snap -->
<DockPanel DockPanel.Dock="Bottom">
<ToggleSwitch IsChecked="{TemplateBinding EnableSnap}"
<ToggleSwitch IsChecked="{Binding EnableSnap, RelativeSource={RelativeSource TemplatedParent}}"
OnContent="Snap On"
OffContent="Snap Off"
HorizontalAlignment="Left"
@ -30,7 +30,7 @@
Margin="4,4,2,4"
Padding="6"
TextAlignment="Left"
Text="{TemplateBinding SnapX}" />
Text="{Binding SnapX, RelativeSource={RelativeSource TemplatedParent}}" />
<Label Grid.Column="2"
Content="SY"
Margin="6,0,6,0"
@ -41,12 +41,12 @@
Margin="2,4,4,4"
Padding="6"
TextAlignment="Left"
Text="{TemplateBinding SnapY}" />
Text="{Binding SnapY, RelativeSource={RelativeSource TemplatedParent}}" />
</Grid>
</DockPanel>
<!-- Grid -->
<DockPanel DockPanel.Dock="Bottom">
<ToggleSwitch IsChecked="{TemplateBinding EnableGrid}"
<ToggleSwitch IsChecked="{Binding EnableGrid, RelativeSource={RelativeSource TemplatedParent}}"
OnContent="Grid On"
OffContent="Grid Off"
HorizontalAlignment="Left"
@ -64,7 +64,7 @@
Margin="4,4,2,4"
Padding="6"
TextAlignment="Left"
Text="{TemplateBinding GridCellWidth}" />
Text="{Binding GridCellWidth, RelativeSource={RelativeSource TemplatedParent}}" />
<Label Grid.Column="2"
Content="CH"
Margin="6,0,6,0"
@ -75,7 +75,7 @@
Margin="2,4,4,4"
Padding="6"
TextAlignment="Left"
Text="{TemplateBinding GridCellHeight}" />
Text="{Binding GridCellHeight, RelativeSource={RelativeSource TemplatedParent}}" />
</Grid>
</DockPanel>
<!-- Width/Height -->
@ -90,7 +90,7 @@
Margin="4,4,2,4"
Padding="6"
TextAlignment="Left"
Text="{TemplateBinding DrawingWidth}" />
Text="{Binding DrawingWidth, RelativeSource={RelativeSource TemplatedParent}}" />
<Label Grid.Column="2"
Content="H"
Margin="6,0,6,0"
@ -101,7 +101,7 @@
Margin="2,4,4,4"
Padding="6"
TextAlignment="Left"
Text="{TemplateBinding DrawingHeight}" />
Text="{Binding DrawingHeight, RelativeSource={RelativeSource TemplatedParent}}" />
</Grid>
</DockPanel>
</ControlTemplate>

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

@ -32,20 +32,21 @@
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch">
<i:Interaction.Behaviors>
<idd:ContextDropBehavior Context="{TemplateBinding DataContext}">
<idd:ContextDropBehavior Context="{Binding DrawingSource, RelativeSource={RelativeSource TemplatedParent}}">
<idd:ContextDropBehavior.Handler>
<behaviors:DrawingDropHandler RelativeTo="{Binding #PART_DrawingNode}" />
<behaviors:DrawingDropHandler DrawingSource="{Binding DrawingSource, RelativeSource={RelativeSource TemplatedParent}}"
RelativeTo="{Binding #PART_DrawingNode}" />
</idd:ContextDropBehavior.Handler>
</idd:ContextDropBehavior>
</i:Interaction.Behaviors>
<Border Background="Transparent"
Width="{TemplateBinding DrawingWidth}"
Height="{TemplateBinding DrawingHeight}"
Width="{Binding DrawingSource.Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding DrawingSource.Height, RelativeSource={RelativeSource TemplatedParent}}"
BoxShadow="4 11 30 1 #3F000000"
ZIndex="-1">
<Panel Background="Transparent"
Width="{TemplateBinding DrawingWidth}"
Height="{TemplateBinding DrawingHeight}">
Width="{Binding DrawingSource.Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding DrawingSource.Height, RelativeSource={RelativeSource TemplatedParent}}">
<Panel.Transitions>
<Transitions>
<TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.1" />
@ -53,56 +54,48 @@
</Panel.Transitions>
<controls:DrawingNode x:Name="PART_DrawingNode"
Background="{DynamicResource DrawingBackground}"
Width="{TemplateBinding DrawingWidth}"
Height="{TemplateBinding DrawingHeight}"
NodesSource="{TemplateBinding NodesSource}"
ConnectorsSource="{TemplateBinding ConnectorsSource}"
InputSource="{TemplateBinding ZoomControl}"
AdornerCanvas="{TemplateBinding AdornerCanvas}"
EnableSnap="{TemplateBinding EnableSnap}"
SnapX="{TemplateBinding SnapX}"
SnapY="{TemplateBinding SnapY}"
EnableGrid="{TemplateBinding EnableGrid}"
GridCellWidth="{TemplateBinding GridCellWidth}"
GridCellHeight="{TemplateBinding GridCellHeight}"
DrawingSource="{Binding DrawingSource, RelativeSource={RelativeSource TemplatedParent}}"
Width="{Binding DrawingSource.Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding DrawingSource.Height, RelativeSource={RelativeSource TemplatedParent}}"
InputSource="{Binding ZoomControl, RelativeSource={RelativeSource TemplatedParent}}"
AdornerCanvas="{Binding AdornerCanvas, RelativeSource={RelativeSource TemplatedParent}}"
ClipToBounds="False">
<!-- TODO:
<controls:DrawingNode.ContextFlyout>
<MenuFlyout>
<MenuItem Header="Cu_t"
Command="{Binding CutNodesCommand}"
Command="{Binding DrawingSource.CutNodesCommand, RelativeSource={RelativeSource TemplatedParent}}"
InputGesture="{OnPlatform macOS=CMD+X, iOS=CMD+X, Default=Ctrl+X}">
<MenuItem.Icon>
<PathIcon Width="16" Height="16" Data="{DynamicResource EditorCutIcon}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_Copy"
Command="{Binding CopyNodesCommand}"
Command="{Binding DrawingSource.CopyNodesCommand, RelativeSource={RelativeSource TemplatedParent}}"
InputGesture="{OnPlatform macOS=CMD+C, iOS=CMD+C, Default=Ctrl+C}">
<MenuItem.Icon>
<PathIcon Width="16" Height="16" Data="{DynamicResource EditorCopyIcon}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_Paste"
Command="{Binding PasteNodesCommand}"
Command="{Binding DrawingSource.PasteNodesCommand, RelativeSource={RelativeSource TemplatedParent}}"
InputGesture="{OnPlatform macOS=CMD+V, iOS=CMD+V, Default=Ctrl+V}">
<MenuItem.Icon>
<PathIcon Width="16" Height="16" Data="{DynamicResource EditorPasteIcon}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="D_uplicate"
Command="{Binding DuplicateNodesCommand}"
Command="{Binding DrawingSource.DuplicateNodesCommand, RelativeSource={RelativeSource TemplatedParent}}"
InputGesture="{OnPlatform macOS=CMD+D, iOS=CMD+D, Default=Ctrl+D}" />
<MenuItem Header="-" />
<MenuItem Header="Select _All"
Command="{Binding SelectAllNodesCommand, FallbackValue={x:Null}}"
Command="{Binding DrawingSource.SelectAllNodesCommand, RelativeSource={RelativeSource TemplatedParent}, FallbackValue={x:Null}}"
InputGesture="{OnPlatform macOS=CMD+A, iOS=CMD+A, Default=Ctrl+A}" />
<MenuItem Header="De_select All"
Command="{Binding DeselectAllNodesCommand, FallbackValue={x:Null}}"
Command="{Binding DrawingSource.DeselectAllNodesCommand, RelativeSource={RelativeSource TemplatedParent}, FallbackValue={x:Null}}"
InputGesture="Escape" />
<MenuItem Header="-" />
<MenuItem Header="_Delete"
Command="{Binding DeleteNodesCommand}"
Command="{Binding DrawingSource.DeleteNodesCommand, RelativeSource={RelativeSource TemplatedParent}}"
InputGesture="Delete">
<MenuItem.Icon>
<PathIcon Width="16" Height="16" Data="{DynamicResource DeleteIcon}" />
@ -110,12 +103,11 @@
</MenuItem>
</MenuFlyout>
</controls:DrawingNode.ContextFlyout>
-->
</controls:DrawingNode>
<Canvas x:Name="PART_AdornerCanvas"
Background="Transparent"
Width="{TemplateBinding DrawingWidth}"
Height="{TemplateBinding DrawingHeight}"
Width="{Binding DrawingSource.Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding DrawingSource.Height, RelativeSource={RelativeSource TemplatedParent}}"
IsHitTestVisible="False"/>
</Panel>
</Border>

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

@ -9,8 +9,8 @@
<Setter Property="Template">
<ControlTemplate>
<Panel Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}">
<Panel Width="{Binding NodeSource.Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding NodeSource.Height, RelativeSource={RelativeSource TemplatedParent}}">
<ContentPresenter x:Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
@ -23,9 +23,9 @@
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
<controls:Pins x:Name="PART_Pins"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
PinsSource="{TemplateBinding PinsSource}"/>
Width="{Binding NodeSource.Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding NodeSource.Height, RelativeSource={RelativeSource TemplatedParent}}"
NodeSource="{Binding NodeSource, RelativeSource={RelativeSource TemplatedParent}}"/>
</Panel>
</ControlTemplate>
</Setter>

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

@ -13,22 +13,18 @@
<Setter Property="Template">
<ControlTemplate>
<ItemsControl x:Name="PART_NodesItemsControl"
ItemsSource="{TemplateBinding NodesSource}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
ItemsSource="{Binding DrawingSource.Nodes, RelativeSource={RelativeSource TemplatedParent}}"
Width="{Binding Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding Height, RelativeSource={RelativeSource TemplatedParent}}"
Background="Transparent"
ClipToBounds="False">
<i:Interaction.Behaviors>
<behaviors:NodesSelectedBehavior />
<!-- TODO: Fix using $parent[controls:DrawingNode] -->
<behaviors:DrawingSelectionBehavior InputSource="{Binding $parent[controls:DrawingNode].InputSource}"
AdornerCanvas="{Binding $parent[controls:DrawingNode].AdornerCanvas}"
EnableSnap="{Binding $parent[controls:DrawingNode].EnableSnap}"
SnapX="{Binding $parent[controls:DrawingNode].SnapX}"
SnapY="{Binding $parent[controls:DrawingNode].SnapY}"
x:CompileBindings="False" />
<behaviors:DrawingPressedBehavior />
<behaviors:DrawingMovedBehavior />
<behaviors:NodesSelectedBehavior DrawingSource="{Binding DrawingSource, RelativeSource={RelativeSource TemplatedParent}}" />
<behaviors:DrawingSelectionBehavior DrawingSource="{Binding DrawingSource, RelativeSource={RelativeSource TemplatedParent}}"
InputSource="{Binding InputSource, RelativeSource={RelativeSource TemplatedParent}}"
AdornerCanvas="{Binding AdornerCanvas, RelativeSource={RelativeSource TemplatedParent}}" />
<behaviors:DrawingPressedBehavior DrawingSource="{Binding DrawingSource, RelativeSource={RelativeSource TemplatedParent}}" />
<behaviors:DrawingMovedBehavior DrawingSource="{Binding DrawingSource, RelativeSource={RelativeSource TemplatedParent}}" />
</i:Interaction.Behaviors>
<ItemsControl.Styles>
<Style Selector="ItemsControl > ContentPresenter" x:DataType="m:INode">
@ -47,7 +43,7 @@
Content="{Binding Content}"
Width="{Binding Width}"
Height="{Binding Height}"
PinsSource="{Binding Pins}" />
NodeSource="{Binding .}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

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

@ -13,8 +13,8 @@
<Setter Property="Template">
<ControlTemplate>
<Ellipse x:Name="PART_Pin"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}" />
Width="{Binding Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding Height, RelativeSource={RelativeSource TemplatedParent}}" />
</ControlTemplate>
</Setter>

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

@ -13,9 +13,9 @@
<Setter Property="Template">
<ControlTemplate>
<ItemsControl x:Name="PART_PinsItemsControl"
ItemsSource="{TemplateBinding PinsSource}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
ItemsSource="{Binding NodeSource.Pins, RelativeSource={RelativeSource TemplatedParent}}"
Width="{Binding NodeSource.Width, RelativeSource={RelativeSource TemplatedParent}}"
Height="{Binding NodeSource.Height, RelativeSource={RelativeSource TemplatedParent}}"
ClipToBounds="False">
<ItemsControl.Styles>
<Style Selector="ItemsControl > ContentPresenter" x:DataType="m:IPin">
@ -44,7 +44,8 @@
Width="{Binding Width}"
Height="{Binding Height}"
Alignment="{Binding Alignment}"
Id="{Binding Name}" />
Id="{Binding Name}"
PinSource="{Binding .}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

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

@ -14,7 +14,7 @@
<Setter Property="Template">
<ControlTemplate>
<ListBox ItemsSource="{TemplateBinding TemplatesSource}"
<ListBox ItemsSource="{Binding TemplatesSource, RelativeSource={RelativeSource TemplatedParent}}"
Background="Transparent">
<ListBox.Resources>
<behaviors:TemplatesListBoxDropHandler x:Key="TemplatesListBoxDropHandler" />
@ -28,7 +28,7 @@
<i:BehaviorCollectionTemplate>
<i:BehaviorCollection>
<idd:ContextDragBehavior />
<behaviors:InsertTemplateOnDoubleTappedBehavior Drawing="{Binding $parent[Toolbox].Drawing}" />
<behaviors:InsertTemplateOnDoubleTappedBehavior />
</i:BehaviorCollection>
</i:BehaviorCollectionTemplate>
</Setter>
@ -42,7 +42,7 @@
Content="{Binding Content}"
Width="{Binding Width}"
Height="{Binding Width}"
PinsSource="{Binding Pins}">
NodeSource="{Binding .}">
<controls:Node.Styles>
<Style Selector="controls|Pins /template/ ItemsControl#PART_PinsItemsControl">
<Setter Property="IsVisible" Value="False" />