7
votes

I'm binding an ItemsControl with Canvas as ItemsPanelTemplate to an ObservableCollection.

I want to make the items draggable using the DraggableExtender as posted in Dragging an image in WPF (I don't want to use transforms - I need to use the Canvas Left and Top properties)

It's defined as :

    <ItemsControl ItemsSource="{Binding Path=Nodes}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Views:NodeView DataContext="{Binding}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Utilities:DraggableExtender.CanDrag" Value="True" />
                <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
                <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>

The DraggableExtender needs the parent of the element to be the Canvas, but the parent of my element (contentpresenter) is null, so the dragging doesn't work.

So the obvious question is - what am I doing wrong ?

1

1 Answers

7
votes

Since the items are not directly inside the canvas, you need to walk up the visual tree until you find the canvas. I usually use the following extension method to do that:

public static T FindAncestor<T>(this DependencyObject obj)
    where T : DependencyObject
{
    DependencyObject tmp = VisualTreeHelper.GetParent(obj);
    while(tmp != null && !(tmp is T))
    {
        tmp = VisualTreeHelper.GetParent(tmp);
    }
    return tmp as T;
}

Put the method above in a static class, and import the namespace where it is declared. In the DraggableExtender code, just replace this line:

Canvas canvas = element.Parent as Canvas;

With this one:

Canvas canvas = element.FindAncestor<Canvas>();