Bind collection of lines to canvas in WPF

binding, data-binding, drawing, shapes, wpf

Solution

Here is an example how you could do it:

The line is defined as follows:

public class Line
{
    public Point From { get; set; }

    public Point To { get; set; }
}

MainWindow.xaml:

<Window x:Class="WpfApplication20.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="300">
    <ItemsControl ItemsSource="{Binding Lines}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Line X1="{Binding From.X}" Y1="{Binding From.Y}"
                      X2="{Binding To.X}" Y2="{Binding To.Y}"
                      Stroke="DarkGray" StrokeThickness="3"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    public ObservableCollection<Line> Lines { get; private set; }

    public MainWindow()
    {
        Lines = new ObservableCollection<Line>
        {
            new Line { From = new Point(100, 20), To = new Point(180, 180) },
            new Line { From = new Point(180, 180), To = new Point(20, 180) },
            new Line { From = new Point(20, 180), To = new Point(100, 20) },
            new Line { From = new Point(20, 50), To = new Point(180, 150) }
        };

        InitializeComponent();
        DataContext = this;
    }
}

In the above example, the lines are static, i.e. if you update the `From` and `To` positions, the UI will not update. If you want the UI to update, you must implement `INotifyPropertyChanged` for the `Line` class.

This sample shows a window that looks like this:

Problem

I have an observable collection of line segments specified by its boundary points. How can I bind it to draw the lines on a canvas? I have seen the solution for shapes using only one point to define the position. But for applying this approach to lines it need awkward precomputations on coordinates to get the position of outer rectangle and make line coordinates relative to it. Is there a way to avoid it?

Original source

Related problems