На данный момент я основывал свое решение в разделе «рисование линии» этого ответа: https://stackoverflow.com/a/2824595/6691231, но у меня возникли проблемы с отображением соединителей на каждом уровне. Вот результат, который я получаю для своего кода:

который, как вы можете видеть, показывает соединители только на первом дочернем уровне, а не на втором. Я попытался добавить все соединители на один холст, но тогда ничего не отображалось. Кто-нибудь может помочь?
Код для рисования пользовательского интерфейса цепочки:
```private void DrawChain(List itemList)
{
items = new ObservableCollection();
Canvas connectorCanvas = new Canvas() { HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch };
mainGrid = new Grid();
mainGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
mainGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
mainGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
//connectorCanvas.Children.Add(mainGrid);
// Set buyer links
Dictionary childDict = itemList.GroupBy(i => i.ParentCode).ToDictionary(i => i.Key, i => i.ToList());
Dictionary parentDict = itemList.GroupBy(i => i.ChildCode).ToDictionary(i => i.Key, i => i.ToList());
ChainLink ourLink = new ChainLink(currentLinkObj, connectorCanvas);
mainGrid.Children.Add(ourLink);
Grid.SetRow(ourLink, 1);
StackPanel childrenVerticalPanel = new StackPanel() { Orientation = Orientation.Vertical };
mainGrid.Children.Add(childrenVerticalPanel);
Grid.SetRow(childrenVerticalPanel, 2);
DrawChildren(ourLink, childrenVerticalPanel, connectorCanvas, childDict, false);
}
private void DrawChildren(ChainLink parentLinkItem, StackPanel parentPanel, Canvas connectorCanvas, Dictionary itemDict, bool reverseConnector)
{
StackPanel chainLinkPanel = new StackPanel() { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Center };
parentPanel.Children.Add(connectorCanvas);
parentPanel.Children.Add(chainLinkPanel);
if (itemDict.TryGetValue(parentLinkItem.Offer.Code, out List children))
{
foreach (ChainItem child in children)
{
object linkObj = chain.FirstOrDefault(o => o.Code == child.ChildCode);
if (linkObj != null)
{
ChainLink childLink = new ChainLink(linkObj, connectorCanvas) { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Top };
ChainConnector connector = new ChainConnector(reverseConnector) { Height = 35, HorizontalAlignment = HorizontalAlignment.Left };
connector.SetBinding(ChainConnector.SourceProperty, new Binding("AnchorPoint") { Source = parentLinkItem });
connector.SetBinding(ChainConnector.DestinationProperty, new Binding("AnchorPoint") { Source = childLink });
connectorCanvas.Children.Add(connector);
if (itemDict.TryGetValue(linkObj.Code, out _))
{
StackPanel verticalPanel = new StackPanel() { Orientation = Orientation.Vertical };
chainLinkPanel.Children.Add(verticalPanel);
verticalPanel.Children.Add(childLink);
Canvas childCanvas = new Canvas() { HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top };
DrawChildren(childLink, verticalPanel, childCanvas, itemDict, reverseConnector);
}
else
{
chainLinkPanel.Children.Add(childLink);
}
}
}
}
}```
Объедините элемент с помощью метода LayoutUpdated:
```public ChainLink(object linkObj, Canvas canvas)
{
this.linkObj= linkObj;
this.canvas = canvas;
LayoutUpdated += OnLayoutUpdated;
InitializeComponent();
}
private void OnLayoutUpdated(object sender, EventArgs e)
{
if (IsLoaded)
{
try
{
Size size = RenderSize;
Point ofs = new Point(size.Width / 2, size.Height);
AnchorPoint = TransformToVisual(canvas).Transform(ofs);
}
catch (Exception ex)
{
// Do nothing yet
}
}
}```
Код разъема:
```public partial class ChainConnector : UserControl
{
public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(Point), typeof(ChainConnector), new FrameworkPropertyMetadata(default(Point)));
public static readonly DependencyProperty DestinationProperty = DependencyProperty.Register("Destination", typeof(Point), typeof(ChainConnector), new FrameworkPropertyMetadata(default(Point)));
private bool reverseDirection;
public Point Source
{
get { return (Point)this.GetValue(SourceProperty); }
set { this.SetValue(SourceProperty, value); }
}
public Point Destination
{
get { return (Point)this.GetValue(DestinationProperty); }
set { this.SetValue(DestinationProperty, value); }
}
public ChainConnector(bool reverseDirection)
{
LineSegment segment = new LineSegment(default(Point), true);
PathFigure figure = new PathFigure(default(Point), new[] { segment }, false);
PathGeometry geometry = new PathGeometry(new[] { figure });
BindingBase sourceBinding = new Binding { Source = this, Path = new PropertyPath(SourceProperty) };
BindingBase destinationBinding = new Binding { Source = this, Path = new PropertyPath(DestinationProperty) };
if (!reverseDirection)
{
BindingOperations.SetBinding(figure, PathFigure.StartPointProperty, sourceBinding);
BindingOperations.SetBinding(segment, LineSegment.PointProperty, destinationBinding);
}
else
{
BindingOperations.SetBinding(figure, PathFigure.StartPointProperty, destinationBinding);
BindingOperations.SetBinding(segment, LineSegment.PointProperty, sourceBinding);
}
Content = new Path
{
Data = geometry,
StrokeThickness = 1,
Stroke = Brushes.Black,
MinWidth = 1,
MinHeight = 1
};
}
}```
Подробнее здесь: https://stackoverflow.com/questions/787 ... ee-diagram