how can I connect these entity boxes?
the boxes are created by clicking a button and they can be dragged. Now I want to connect them with a line or something.
Here is a quick and dirty implementation:
the class that represents the connection:
public partial class Connection
{
public MyBox Box1 { get; set; }
public MyBox Box2 { get; set; }
public Line Line { get; set; }
}
To create a new connection I've used a basic form: name of source, destination and a button:
<StackPanel Orientation="Horizontal" Grid.Row="3">
<TextBox Width="100" Text="{Binding From,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
<TextBlock Text=" ----> " />
<TextBox Width="100" Text="{Binding To,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
<Button Content="Connect" Click="Button_Click_2" />
</StackPanel>
Here is the handler:
public string From { get; set; }
public string To { get; set; }
private IList<Connection> connections = new List<Connection>();
private void Button_Click_2(object sender, RoutedEventArgs e)
{
MyBox box1 = boxes.Single(b => b.Header == From);
MyBox box2 = boxes.Single(b => b.Header == To);
Connection conn = new Connection { Box1 = box1, Box2 = box2, Line = new Line { StrokeThickness = 1, Stroke = Brushes.Black } };
connections.Add(conn);
RefreshLinesPositions();
panel.Children.Add(conn.Line);
}
And the RefreshLinesPositions code:
private void RefreshLinesPositions()
{
foreach (Connection conn in connections)
{
Point p1 = conn.Box1.TranslatePoint(new Point(0, 0), panel);
Point p2 = conn.Box2.TranslatePoint(new Point(0, 0), panel);
double t1 = p1.Y;
double b1 = p1.Y + conn.Box1.ActualHeight;
double l1 = p1.X;
double r1 = p1.X + conn.Box1.ActualWidth;
double t2 = p2.Y;
double b2 = p2.Y + conn.Box2.ActualHeight;
double l2 = p2.X;
double r2 = p2.X + conn.Box2.ActualWidth;
if (r1 < l2)
{
conn.Line.X1 = r1;
conn.Line.Y1 = t1 + (b1 - t1) / 2;
conn.Line.X2 = l2;
conn.Line.Y2 = t2 + (b2 - t2) / 2;
conn.Line.Visibility = Visibility.Visible;
}
else if (r2 < l1)
{
conn.Line.X1 = r2;
conn.Line.Y1 = t2 + (b2 - t2) / 2;
conn.Line.X2 = l1;
conn.Line.Y2 = t1 + (b1 - t1) / 2;
conn.Line.Visibility = Visibility.Visible;
}
else if (b1 < t2)
{
conn.Line.X1 = l1 + (r1 - l1) / 2;
conn.Line.Y1 = b1;
conn.Line.X2 = l2 + (r2 - l2) / 2;
conn.Line.Y2 = t2;
conn.Line.Visibility = Visibility.Visible;
}
else if (b2 < t1)
{
conn.Line.X1 = l1 + (r1 - l1) / 2;
conn.Line.Y1 = t1;
conn.Line.X2 = l2 + (r2 - l2) / 2;
conn.Line.Y2 = b2;
conn.Line.Visibility = Visibility.Visible;
}
else
{
conn.Line.Visibility = System.Windows.Visibility.Collapsed;
}
}
And you call RefreshLinesPositions whenever a box is moved:
private void Box_MouseMove(object sender, MouseEventArgs e)
{
if (draggedBox != null)
{
...
RefreshLinesPositions();
}
}
EDIT: for the nodes
The new RefreshLinesPosition version:
private void RefreshLinesPositions()
{
foreach (Connection conn in connections)
{
Point p1 = conn.Box1.TranslatePoint(new Point(0, 0), panel);
Point p2 = conn.Box2.TranslatePoint(new Point(0, 0), panel);
double t1 = p1.Y;
double b1 = p1.Y + conn.Box1.ActualHeight;
double l1 = p1.X;
double r1 = p1.X + conn.Box1.ActualWidth;
double t2 = p2.Y;
double b2 = p2.Y + conn.Box2.ActualHeight;
double l2 = p2.X;
double r2 = p2.X + conn.Box2.ActualWidth;
if (r1 < l2)
{
conn.Line.X1 = r1;
conn.Line.Y1 = t1 + (b1 - t1) / 2;
conn.Line.X2 = l2;
conn.Line.Y2 = t2 + (b2 - t2) / 2;
conn.Line.Visibility = Visibility.Visible;
conn.Node1.Text.RenderTransform = new TranslateTransform(r1, t1 + (b1 - t1) / 2);
conn.Node2.Text.RenderTransform = new TranslateTransform(l2 - conn.Node2.Text.ActualWidth, t2 + (b2 - t2) / 2);
}
else if (r2 < l1)
{
conn.Line.X1 = l1;
conn.Line.Y1 = t1 + (b1 - t1) / 2;
conn.Line.X2 = r2;
conn.Line.Y2 = t2 + (b2 - t2) / 2;
conn.Line.Visibility = Visibility.Visible;
conn.Node1.Text.RenderTransform = new TranslateTransform(l1 - conn.Node1.Text.ActualWidth, t1 + (b1 - t1) / 2);
conn.Node2.Text.RenderTransform = new TranslateTransform(r2, t2 + (b2 - t2) / 2);
}
else if (b1 < t2)
{
conn.Line.X1 = l1 + (r1 - l1) / 2;
conn.Line.Y1 = b1;
conn.Line.X2 = l2 + (r2 - l2) / 2;
conn.Line.Y2 = t2;
conn.Line.Visibility = Visibility.Visible;
conn.Node1.Text.RenderTransform = new TranslateTransform(l1 + (r1 - l1) / 2, b1);
conn.Node2.Text.RenderTransform = new TranslateTransform(l2 + (r2 - l2) / 2, t2 - conn.Node2.Text.ActualHeight);
}
else if (b2 < t1)
{
conn.Line.X1 = l1 + (r1 - l1) / 2;
conn.Line.Y1 = t1;
conn.Line.X2 = l2 + (r2 - l2) / 2;
conn.Line.Y2 = b2;
conn.Line.Visibility = Visibility.Visible;
conn.Node1.Text.RenderTransform = new TranslateTransform(l1 + (r1 - l1) / 2, t1 - conn.Node1.Text.ActualHeight);
conn.Node2.Text.RenderTransform = new TranslateTransform(l2 + (r2 - l2) / 2, b2);
}
else
{
conn.Line.Visibility = System.Windows.Visibility.Collapsed;
}
}
}
The new event handler:
private void Button_Click_2(object sender, RoutedEventArgs e)
{
MyBox box1 = boxes.Single(b => b.Header == From);
MyBox box2 = boxes.Single(b => b.Header == To);
Connection conn = new Connection
{
Box1 = box1,
Box2 = box2,
Line = new Line { StrokeThickness = 1, Stroke = Brushes.Black },
Node1 = new Node { Text = new TextBox() },
Node2 = new Node { Text = new TextBox() }
};
connections.Add(conn);
panel.Children.Add(conn.Line);
panel.Children.Add(conn.Node1.Text);
panel.Children.Add(conn.Node2.Text);
RefreshLinesPositions();
}
I've used this for representing nodes:
public partial class Node
{
public string Title { get; set; }
public TextBox Text { get; set; }
}