It is _important_ to understand how components are named and what's their role in the visual tree of the editor to understand the code and the documentation.

## Hierarchy and terminology

The root component is an [editor](Editor-Overview) which holds [nodes](Nodes-Overview) and [connections](Connections-Overview) together with a few additional UI elements such as a [selection rectangle](Editor-Overview#selecting) and a [pending connection](Connections-Overview#pending-connection) in order to make the editor interactive.

Nodes are containers for [connectors](Connectors-Overview) or the node itself can be a connector (e.g. [State Node](Nodes-Overview#4-the-statenode-control)).

Connectors can create pending connections that can become real connections when completed.

_A picture is worth a thousand words_

![nodes-hierarchy](https://user-images.githubusercontent.com/12727904/192028123-e2847f29-6517-4731-8672-f5d8356dead0.png)

## Content Layers

You may wonder how a node can be a connector itself and still behave like a normal node. The editor contains three big layers which help solve this problem:

1. The items layer (`NodifyEditor.ItemsSource`) - here, each control is wrapped inside an [Item Container](ItemContainer-Overview) making it selectable, draggable, etc and it is possible to have any control rendered (e.g a connector, a text block).
2. The connections layer (`NodifyEditor.Connections`) - this is where all the [connections](Connections-Overview) coexist and are rendered behind the items layer by default
3. The decorators layer (`NodifyEditor.Decorators`) - here, each control is given a location inside the graph

Having those layers separated enables the possibility of asynchronously loading each one of them.

## Using an existing theme

Merge one of the following themes into your resource dictionary in `App.xaml`:

- Dark theme (default theme if not specified):

```xml
<ResourceDictionary Source="pack://application:,,,/Nodify;component/Themes/Dark.xaml" />
```

- Light theme:

```xml
<ResourceDictionary Source="pack://application:,,,/Nodify;component/Themes/Light.xaml" />
```

- Nodify theme:

```xml
<ResourceDictionary Source="pack://application:,,,/Nodify;component/Themes/Nodify.xaml" />
```

## A minimal example

Import the `nodify` namespace: `xmlns:nodify="https://miroiu.github.io/nodify"` or `xmlns:nodify="clr-namespace:Nodify;assembly=Nodify"` in your file and create an instance of the editor `<nodify:NodifyEditor />`. If you start the application, you will see an empty space where you can create a selection rectangle.

> Tip: Drag the selection rectangle near the edge of the editor area and the screen will automatically move in that direction.

### Adding nodes

Now we're going to display a few nodes. Let's create the viewmodels and bind them to the view.

```csharp
public class NodeViewModel
{
    public string Title { get; set; }
}

public class EditorViewModel
{
    public ObservableCollection<NodeViewModel> Nodes { get; } = new ObservableCollection<NodeViewModel>();

    public EditorViewModel()
    {
        Nodes.Add(new NodeViewModel { Title = "Welcome" });
    }
}
```

The view model can be of any shape, but the view for the node is generated by the `ItemTemplate`. (The same result would be achieved by having the DataTemplate inside NodifyEditor.Resources)

```xml
<nodify:NodifyEditor ItemsSource="{Binding Nodes}">
    <nodify:NodifyEditor.DataContext>
        <local:EditorViewModel />
    </nodify:NodifyEditor.DataContext>

    <nodify:NodifyEditor.ItemTemplate>
        <DataTemplate DataType="{x:Type local:NodeViewModel}">
            <nodify:Node Header="{Binding Title}" />
        </DataTemplate>
    </nodify:NodifyEditor.ItemTemplate>

</nodify:NodifyEditor>
```

Notice how we bind the `Header` of the `Node` to display the `Title`. For more node types and customization please check out the [Nodes overview](Nodes-Overview).

### Connecting nodes

Alright, now let's add more nodes and connect them together. First, we need a representation of a connector and some collections on the node to store our connectors.

```csharp
public class ConnectorViewModel
{
    public string Title { get; set; }
}

public class NodeViewModel
{
    public string Title { get; set; }

    public ObservableCollection<ConnectorViewModel> Input { get; set; } = new ObservableCollection<ConnectorViewModel>();
    public ObservableCollection<ConnectorViewModel> Output { get; set; } = new ObservableCollection<ConnectorViewModel>();
}

public class EditorViewModel
{
    public ObservableCollection<NodeViewModel> Nodes { get; } = new ObservableCollection<NodeViewModel>();

    public EditorViewModel()
    {
        Nodes.Add(new NodeViewModel
        {
            Title = "Welcome",
            Input = new ObservableCollection<ConnectorViewModel>
            {
                new ConnectorViewModel
                {
                    Title = "In"
                }
            },
            Output = new ObservableCollection<ConnectorViewModel>
            {
                new ConnectorViewModel
                {
                    Title = "Out"
                }
            }
        });
    }
}
```

And bind them to the view. (We used the built-in `NodeInput` and `NodeOutput` for the view, but there are [other connectors](Connectors-Overview) too. Or you can create your own, depending on your needs.)

```xml
<nodify:Node Header="{Binding Title}"
             Input="{Binding Input}"
             Output="{Binding Output}">
  <nodify:Node.InputConnectorTemplate>
      <DataTemplate DataType="{x:Type local:ConnectorViewModel}">
          <nodify:NodeInput Header="{Binding Title}" />
      </DataTemplate>
  </nodify:Node.InputConnectorTemplate>

  <nodify:Node.OutputConnectorTemplate>
      <DataTemplate DataType="{x:Type local:ConnectorViewModel}">
          <nodify:NodeOutput Header="{Binding Title}" />
      </DataTemplate>
  </nodify:Node.OutputConnectorTemplate>
</nodify:Node>
```

The `Node` control supports `Input` and `Output` connectors and the way you customize these is by overwriting the default template for the `InputConnectorTemplate`, respectively the `OutputConnectorTemplate`.

Clicking and dragging a wire from the `Input` or `Output` connector will create a [pending connection](Connections-Overview#pending-connection) that we can transform into a real connection.

**The most complicated part of Nodify is how you bind the connections to their connectors.** Let's create the ViewModel for the connection and add a list of connections in the `EditorViewModel`.

```csharp
public class ConnectionViewModel
{
    public ConnectorViewModel Source { get; set; }
    public ConnectorViewModel Target { get; set; }
}

public class EditorViewModel
{
    public ObservableCollection<NodeViewModel> Nodes { get; } = new ObservableCollection<NodeViewModel>();
    public ObservableCollection<ConnectionViewModel> Connections { get; } = new ObservableCollection<ConnectionViewModel>();

    public EditorViewModel()
    {
        var welcome = new NodeViewModel
        {
            Title = "Welcome",
            Input = new ObservableCollection<ConnectorViewModel>
            {
                new ConnectorViewModel
                {
                    Title = "In"
                }
            },
            Output = new ObservableCollection<ConnectorViewModel>
            {
                new ConnectorViewModel
                {
                    Title = "Out"
                }
            }
        };

        var nodify = new NodeViewModel
        {
            Title = "To Nodify",
            Input = new ObservableCollection<ConnectorViewModel>
            {
                new ConnectorViewModel
                {
                    Title = "In"
                }
            }
        };

        Nodes.Add(welcome);
        Nodes.Add(nodify);

        Connections.Add(new ConnectionViewModel
        {
            Source = welcome.Output[0],
            Target = nodify.Input[0]
        });
    }
}
```

Then update the `ConnectorViewModel` to have an `Anchor` point that the connection can attach to. (This needs to be reactive, so we're gonna implement INotifyPropertyChanged in the view model).

> Note: The `Point` type must be from System.Windows.

```csharp
public class ConnectorViewModel : INotifyPropertyChanged
{
    private Point _anchor;
    public Point Anchor
    {
        set
        {
            _anchor = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Anchor)));
        }
        get => _anchor;
    }

    public string Title { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;
}
```

Bind the `Anchor` to the connector's view as `Mode=OneWayToSource`. And also set the `IsConnected` to `True` to receive `Anchor` updates.

```xml
<nodify:Node.InputConnectorTemplate>
    <DataTemplate DataType="{x:Type local:ConnectorViewModel}">
        <nodify:NodeInput Header="{Binding Title}"
                          IsConnected="True"
                          Anchor="{Binding Anchor, Mode=OneWayToSource}" />
    </DataTemplate>
</nodify:Node.InputConnectorTemplate>

<nodify:Node.OutputConnectorTemplate>
    <DataTemplate DataType="{x:Type local:ConnectorViewModel}">
        <nodify:NodeOutput Header="{Binding Title}"
                           IsConnected="True"
                           Anchor="{Binding Anchor, Mode=OneWayToSource}"  />
    </DataTemplate>
</nodify:Node.OutputConnectorTemplate>
```

And bind the connections to the view and let them use our `ConnectorViewModel`'s `Anchor` in the `ConnectionTemplate`. For more customization, please refer to [connections overview](Connections-Overview).

```xml
<nodify:NodifyEditor ItemsSource="{Binding Nodes}"
                     Connections="{Binding Connections}">
    ...
    <nodify:NodifyEditor.ConnectionTemplate>
        <DataTemplate DataType="{x:Type local:ConnectionViewModel}">
            <nodify:LineConnection Source="{Binding Source.Anchor}"
                                   Target="{Binding Target.Anchor}" />
        </DataTemplate>
    </nodify:NodifyEditor.ConnectionTemplate>
    ...
```

If you start the application now, you'll see that there is a connection and if you drag the nodes around, it will follow them.

Now let's add the `IsConnected` property to the `ConnectorViewModel` so we can set it whenever it is truly connected or not. And update the `ConnectionViewModel` to connect them automatically on construction.

```csharp
public class ConnectorViewModel : INotifyPropertyChanged
{
    private Point _anchor;
    public Point Anchor
    {
        set
        {
            _anchor = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Anchor)));
        }
        get => _anchor;
    }

    private bool _isConnected;
    public bool IsConnected
    {
        set
        {
            _isConnected = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsConnected)));
        }
        get => _isConnected;
    }

    public string Title { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;
}

public class ConnectionViewModel
{
    public ConnectionViewModel(ConnectorViewModel source, ConnectorViewModel target)
    {
        Source = source;
        Target = target;

        Source.IsConnected = true;
        Target.IsConnected = true;
    }

    public ConnectorViewModel Source { get; }
    public ConnectorViewModel Target { get; }
}
```

And don't forget to bind it in the connector template.

```xml
IsConnected="{Binding IsConnected}"
```

### Materializing pending connections

The [PendingConnection](Connections-Overview#pending-connection) starts from a `Source` and will be completed when dropped on a `Target`. The source is _always_ a connector, and the target can be a [Connector](Connectors-Overview), an [ItemContainer](ItemContainer-Overview) or `null` otherwise. We will only care about other connectors for now. When the connection starts, the `StartedCommand` is executed which receives the `Source` as the parameter. When the connection completes, the `CompletedCommand` is executed which receives the `Target` as the parameter.

To create the commands we need an implementation of `ICommand`. I will use the following generic implementation:

```csharp
public class DelegateCommand<T> : ICommand
{
    private readonly Action<T> _action;
    private readonly Func<T, bool>? _condition;

    public event EventHandler? CanExecuteChanged;

    public DelegateCommand(Action<T> action, Func<T, bool>? executeCondition = default)
    {
        _action = action ?? throw new ArgumentNullException(nameof(action));
        _condition = executeCondition;
    }

    public bool CanExecute(object? parameter)
    {
        if (parameter is T value)
        {
            return _condition?.Invoke(value) ?? true;
        }

        return _condition?.Invoke(default!) ?? true;
    }

    public void Execute(object? parameter)
    {
        if (parameter is T value)
        {
            _action(value);
        }
        else
        {
            _action(default!);
        }
    }

    public void RaiseCanExecuteChanged()
        => CanExecuteChanged?.Invoke(this, new EventArgs());
}
```

Let's implement the pending connection view model and add it to the `EditorViewModel`.

```csharp
public class PendingConnectionViewModel
{
    private readonly EditorViewModel _editor;
    private ConnectorViewModel _source;

    public PendingConnectionViewModel(EditorViewModel editor)
    {
        _editor = editor;
        StartCommand = new DelegateCommand<ConnectorViewModel>(source => _source = source);
        FinishCommand = new DelegateCommand<ConnectorViewModel>(target =>
        {
            if (target != null)
                _editor.Connect(_source, target);
        });
    }

    public ICommand StartCommand { get; }
    public ICommand FinishCommand { get; }
}

public class EditorViewModel
{
    public PendingConnectionViewModel PendingConnection { get; }

    ...

    public EditorViewModel()
    {
        PendingConnection = new PendingConnectionViewModel(this);
        ...
    }

    ...

    public void Connect(ConnectorViewModel source, ConnectorViewModel target)
    {
        Connections.Add(new ConnectionViewModel(source, target));
    }
}
```

And bind it to the view.

```xml
<nodify:NodifyEditor PendingConnection="{Binding PendingConnection}">
...
    <nodify:NodifyEditor.PendingConnectionTemplate>
        <DataTemplate DataType="{x:Type local:PendingConnectionViewModel}">
            <nodify:PendingConnection StartedCommand="{Binding StartCommand}"
                                      CompletedCommand="{Binding FinishCommand}"
                                      AllowOnlyConnectors="True" />
        </DataTemplate>
    </nodify:NodifyEditor.PendingConnectionTemplate>
...
</nodify:NodifyEditor>
```

That's all. You should be able to create connections between connectors now.

### Removing connections

To remove connections you just have to listen for a disconnect event from the connector itself or from the editor and remove the connection that has the connector as the source or target. To keep it simple, we're gonna implement the `DisconnectConnectorCommand` for the `NodifyEditor`. Let's add it to the `EditorViewModel` first.

```csharp
public class EditorViewModel
{
    public ICommand DisconnectConnectorCommand { get; }

    ...

    public EditorViewModel()
    {
        DisconnectConnectorCommand = new DelegateCommand<ConnectorViewModel>(connector =>
        {
            var connection = Connections.First(x => x.Source == connector || x.Target == connector);
            connection.Source.IsConnected = false;  // This is not correct if there are multiple connections to the same connector
            connection.Target.IsConnected = false;
            Connections.Remove(connection);
        });

        ...
    }
}
```

Now we have to bind the command to the editor view.

```xml
<nodify:NodifyEditor ItemsSource="{Binding Nodes}"
                     Connections="{Binding Connections}"
                     PendingConnection="{Binding PendingConnection}"
                     DisconnectConnectorCommand="{Binding DisconnectConnectorCommand}">
  ...

</nodify:NodifyEditor>
```

### Controlling node location

As you can see, the nodes are always in the top left corner of the screen. That's because they are at location (0, 0) inside the graph. Let's change that!

Add a `Location` property of type `System.Windows.Point` in the `NodeViewModel` that raises PropertyChanged events.

```csharp
public class NodeViewModel : INotifyPropertyChanged
{
    private Point _location;
    public Point Location
    {
        set
        {
            _location = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Location)));
        }
        get => _location;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    ...
}
```

And bind it to the view.

```xml
<nodify:NodifyEditor ItemsSource="{Binding Nodes}"
                     Connections="{Binding Connections}"
                     PendingConnection="{Binding PendingConnection}">

    <nodify:NodifyEditor.ItemContainerStyle>
        <Style TargetType="{x:Type nodify:ItemContainer}">
            <Setter Property="Location"
                    Value="{Binding Location}" />
        </Style>
    </nodify:NodifyEditor.ItemContainerStyle>

    ...

</nodify:NodifyEditor>
```

> Note: I used the `ItemContainerStyle` to bind the location of the node. Please check out the [ItemContainer overview](ItemContainer-Overview) for more info.

Now you can set the location of the nodes when constructed.

## Drawing a grid

Drawing a simple grid is just a matter of creating a grid brush, applying the editor transform to it, and using the brush as the `Background` of the editor.

Because the grid we are drawing is made of lines and is not filled, the `Background` of the editor will have some transparency, meaning that we'll see the background color of the control below. To solve this, wrap the editor in a `Grid` and set its `Background` or set the `Background` of the `Window`.

Use the `ViewportTransform` dependency property to have the grid move with the view.

> Note: The example uses static resources which are provided by the selected theme in `App.xaml`.

```xml
<Window x:Class="MyProject.MainWindow"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:nodify="https://miroiu.github.io/nodify"
        mc:Ignorable="d">

    <Window.Resources>
        <GeometryDrawing x:Key="SmallGridGeometry"
                        Geometry="M0,0 L0,1 0.03,1 0.03,0.03 1,0.03 1,0 Z"
                        Brush="{StaticResource NodifyEditor.SelectionRectangleBackgroundBrush}" />

        <GeometryDrawing x:Key="LargeGridGeometry"
                        Geometry="M0,0 L0,1 0.015,1 0.015,0.015 1,0.015 1,0 Z"
                        Brush="{StaticResource NodifyEditor.SelectionRectangleBackgroundBrush}" />

        <DrawingBrush x:Key="SmallGridLinesDrawingBrush"
                    TileMode="Tile"
                    ViewportUnits="Absolute"
                    Viewport="0 0 20 20"
                    Transform="{Binding ViewportTransform, ElementName=Editor}"
                    Drawing="{StaticResource SmallGridGeometry}" />

        <DrawingBrush x:Key="LargeGridLinesDrawingBrush"
                    TileMode="Tile"
                    ViewportUnits="Absolute"
                    Opacity="0.5"
                    Viewport="0 0 100 100"
                    Transform="{Binding ViewportTransform, ElementName=Editor}"
                    Drawing="{StaticResource LargeGridGeometry}" />
    </Window.Resources>

    <Grid Background="{StaticResource NodifyEditor.BackgroundBrush}">
        <nodify:NodifyEditor x:Name="Editor" Background="{StaticResource SmallGridLinesDrawingBrush}" />

        <Grid Background="{StaticResource LargeGridLinesDrawingBrush}"
              Panel.ZIndex="-2" />
    </Grid>
</Window>
```

> Tip: Right-click and drag the screen around to move the view and use the mouse wheel to zoom in and out.
