Canvas, как панель для набора элементов, и Behaviors

247
21 апреля 2017, 17:50

Мне нужно в качестве панели для элементов указать Canvas и подключить возможность перемещать элементы в ней.

Есть вот такая разметка.

<ItemsControl ItemsSource="{Binding MapObjects}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas IsItemsHost="True"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding}">
                <i:Interaction.Behaviors>
                    <behaviors:DragBehavior/>
                </i:Interaction.Behaviors>
            </ContentControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding Position.X}"/>
            <Setter Property="Canvas.Top" Value="{Binding Position.Y}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

Из разметки видно, что для того, чтобы биндиться к аттачед свойствам Canvas.Top/Left понадобилось делать биндинг через стиль ContentPresenter, потому что каждый элемент оборачивается в ContentPresenter. А вот Behaviors я через стили указать не могу, потому что дизайнер ругается вот таким матом

Свойство Behaviors не является DependencyProperty

Пробовал сделать так

<Setter Property="i:Interaction.Behaviors">
    <Setter.Value>
        <behaviors:DragBehavior/>
    </Setter.Value>
</Setter>

А в том виде, в котором это сейчас, оно не работает, потому что AssociatedObject в коде DragBehavior у меня является ContentControl. Я, конечно, могу найти нужный мне элемент по визуальному дереву, но что то мне подсказывает, что есть более изящный способ, который не будет так жестко привязан к разметке

Answer 1

Нашел решение здесь http://stackoverflow.com/a/4779168/5938996

Вот что получилось

<ItemsControl ItemsSource="{Binding MapObjects}">
    <ItemsControl.Resources>
        <local:MyBehaviors x:Key="myBehaviors" x:Shared="False">
            <behaviors:DragBehavior/>
        </local:MyBehaviors>
    </ItemsControl.Resources>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas IsItemsHost="True"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding}">
            </ContentControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding X, Mode=TwoWay}"/>
            <Setter Property="Canvas.Top" Value="{Binding Y, Mode=TwoWay}"/>
            <Setter Property="local:SupplementaryInteraction.Behaviors" Value="{StaticResource myBehaviors}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

И код

public class MyBehaviors : List<Behavior>
{
}
public static class SupplementaryInteraction
{
    public static MyBehaviors GetBehaviors(DependencyObject obj)
    {
        return (MyBehaviors)obj.GetValue(BehaviorsProperty);
    }
    public static void SetBehaviors(DependencyObject obj, MyBehaviors value)
    {
        obj.SetValue(BehaviorsProperty, value);
    }
    public static readonly DependencyProperty BehaviorsProperty =
        DependencyProperty.RegisterAttached("Behaviors", typeof(MyBehaviors), typeof(SupplementaryInteraction), new UIPropertyMetadata(null, OnPropertyBehaviorsChanged));
    private static void OnPropertyBehaviorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behaviors = Interaction.GetBehaviors(d);
        foreach (var behavior in e.NewValue as MyBehaviors) behaviors.Add(behavior);
    }
}

Если кратко, Behaviors не является DependencyProperty. Исправляем это искусственно.

READ ALSO
Как прицепиться к окну?

Как прицепиться к окну?

Можно ли как то привязать окно моей программы к окну другой программы?

200
Удалить из списка значения, которых нет в другом списке

Удалить из списка значения, которых нет в другом списке

Для того, чтобы удалить все элементы подходящие под условие можно использовать метод RemoveAll

236
Повторный вызов метода OnCreate()

Повторный вызов метода OnCreate()

При развертывании проекта (чтение sms-сообщений), после получения сообщения приложение открывается три разаПо-моему OnCreate() запускается несколько...

222
Как завершить tcp соединение для windows.networking.sockets windows phone 8.1 c#

Как завершить tcp соединение для windows.networking.sockets windows phone 8.1 c#

Как завершить tcp соединение для windowsnetworking

203