0

I have a class that records the startpoint and endpoint of a line. The elements of this class are added to an Observable Collection, which serves as the ItemsSource of my ItemsControl.

Here is the relevant part of the XAML:

<ItemsControl Name="PathControl">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Line
                                Name="Path"
                                Stroke="Red"
                                StrokeThickness="4"
                                X1="{Binding
                                    StartCoordinates.X,
                                    Mode=TwoWay,
                                    UpdateSourceTrigger=PropertyChanged}"

                                Y1="{Binding
                                    StartCoordinates.Y,
                                    Mode=TwoWay,
                                    UpdateSourceTrigger=PropertyChanged}"
                                X2="{Binding
                                    EndCoordinates.X,
                                    Mode=TwoWay,
                                    UpdateSourceTrigger=PropertyChanged}"

                                Y2="{Binding
                                    endCoordinates.Y,
                                    Mode=TwoWay,
                                    UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

And here is the corresponding class:

public class VisualPath: INotifyPropertyChanged
{

    public VisualPath(Point start, Point end)
    {
        this.startCoordinates = start;
        this.endCoordinates = end;
    }


    Point startCoordinates;
    public Point StartCoordinates
    {
        get
        {
            return startCoordinates;
        }

        set
        {
            startCoordinates = value;
            OnPropertyChanged();
        }
    }

    Point endCoordinates;
    public Point EndCoordinates
    {
        get
        {
            return endCoordinates;
        }

        set
        {
            endCoordinates = value;
            OnPropertyChanged();
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

This is the relevant part of my MainWindow:

public MainWindow()
{          
    InitializeComponent();
    PathControl.ItemsSource = PathElements = new ObservableCollection<VisualPath>();           
}

I would like to create multiple pairs of buttons and connect them with the lines. To do this, I record the absolute position of two buttons relative to the grid with a click event. I store the position of the first button in a Position variable (tempPoint) and when I click on the second button (the target) a new line is supposed to be added to the collection (which happens) with the position of the 1st button as its X1 and Y1 (start point) from tempPoint and the position of the second button as its X2 and Y2 (end point).

Here are the methods handling the click events:

private void firstButton_Click(object sender, RoutedEventArgs e)
{
    Button pathInitiator = sender as Button;
    if (pathInitiator != null)
    {
        tempPoint = pathInitiator.TranslatePoint(new Point(0, 0), MainGrid);
    }
    else
    {
        MessageBox.Show("Not Button");
    }
}

private void secondButton_Click(object sender, RoutedEventArgs e)
{
    Button pathTerminator = sender as Button;
    if (pathTerminator != null)
    {
        GeneralTransform end = pathTerminator.TransformToVisual(this);
        Point endPoint = end.Transform(new Point(0, 0));
        PathElements.Add(new VisualPath(tempPoint, endPoint));
        //PathElements.Add(new VisualPath(new Point(0, 0), new Point(200, 200)));
    }

}

Although the position of the first instance of first button is usually captured correctly, the end point of the line is always misplaced and any other instances of the first button as well. The lines displayed always appear to have flipped or shifted, even when I tried to add multiple lines on top of each other (as shown by the lines commented out), the new lines always appear underneath the previous one. Is my wiring bad, or there is something I don't get with how lines work in WPF?

EDIT: Thanks to the comments, now the first instance of the pair works the way it should:

The edges of the buttons are connected by a line as expected

But any other instances of the pair are misplaced: The pair is not connected, although the very same method is used

oneManArmin
  • 606
  • 6
  • 24
  • You have a type in your Y2 binding. endCoordinates.Y should be EndCoordinates.Y with a capital E. Apart from this, what is your exact issue? What is the expected result and the result that you are seeing? – mm8 Feb 08 '17 at 13:00
  • Thanks, this helped a little: now my first instance of the pairs works as they should. But subsequent instances are misplaced. It might be due to not setting my Point variable back to its initial state (0, 0), although, I tried it to no avail. – oneManArmin Feb 08 '17 at 13:20
  • As a note, setting `Mode=TwoWay` (and hence also `UpdateSourceTrigger=PropertyChanged`) doesn't seem to make sense on the X1, Y1, X2 and Y2 bindings. Besides that, instead of a Line you may probably better use a Path with a LineGeometry, where you could directly bind the `StartPoint` and `EndPoint` properties. – Clemens Feb 08 '17 at 13:22
  • The Update Trigger and the TwoWay binding is for a future feature in which the end of the lines would follow wherver I drag the buttons. As for the desired effect, I edit my question in a minute. – oneManArmin Feb 08 '17 at 13:47

1 Answers1

0

If you want the lines to end up on top of each other you could set the ItemsPanelTemplate of the ItemsControl to a Grid:

<ItemsControl Name="PathControl">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <Line
                        Name="Path"
                        Stroke="Red"
                        StrokeThickness="4"
                        X1="{Binding
                            StartCoordinates.X,
                            Mode=TwoWay,
                            UpdateSourceTrigger=PropertyChanged}"

                        Y1="{Binding
                            StartCoordinates.Y,
                            Mode=TwoWay,
                            UpdateSourceTrigger=PropertyChanged}"
                        X2="{Binding
                            EndCoordinates.X,
                            Mode=TwoWay,
                            UpdateSourceTrigger=PropertyChanged}"

                        Y2="{Binding
                            EndCoordinates.Y,
                            Mode=TwoWay,
                            UpdateSourceTrigger=PropertyChanged}" />
                <TextBlock Text="{Binding EndCoordinates.Y}" />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Well, it was just a way to test wether my xaml works or not, so it is not my intent to pile up lines this way :) – oneManArmin Feb 08 '17 at 14:05
  • It may be an idea to state what your idea is then...? – mm8 Feb 08 '17 at 14:09
  • _I would like to create multiple pairs of buttons and connect them with the lines._ Is this not descriptive enough with the pictures enclosed ? :) – oneManArmin Feb 08 '17 at 14:18
  • No, it is clearly not. Please provide a minimal, complete, and verifiable example including all relevant code snippets: http://stackoverflow.com/help/mcve – mm8 Feb 08 '17 at 14:22
  • I will, but first I would like to know, if there is anything wrong with how I approach the problem. Giving back the exact same and testable conditions would be hard anyway, since, I have multiple bindings and what I call a button for the sake of simplicity is actually an element of multiple layers bound to another Observable Collection (which nonetheless works w/o the new feature). So I move on only, if my fundamental idea is not flawed. But thanks for pointing this out. – oneManArmin Feb 08 '17 at 14:34