Silverlight: как перемещать элементы в ItemsControl в Canvas - PullRequest
1 голос
/ 17 декабря 2011

У меня есть ItemsControl, который показывает UserControl как ItemTemplate. У этого есть Панель Предметов Холста.

   <ItemsControl ItemsSource="{Binding Path=MyItems}" Margin="200,20,0,0">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <local:MyControl Margin="10,10,10,10"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Height="2000" Width="2000"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

Я хочу переместить элементы управления на холст при перетаскивании мышью

MyControl имеет поведение:

<UserControl x:Class="MyControl">

    <StackPanel x:Name="LayoutRoot" >
        <Grid Background="LightBlue" Height="20">
    </StackPanel>
<Interactivity:Interaction.Behaviors>
    <Behavior:DragControlBehavior />
</Interactivity:Interaction.Behaviors>
</UserControl>

DragControlBehavior устанавливает присоединенные свойства Canvas в MouseMove над элементом управления

[Обновление] - Вот полный исходный код поведения

public class DragControlBehavior : Behavior<MyControl>
{
    private DependencyObject _parent;
    private bool _isMouseCaptured = false;

    protected override void OnAttached()
    {
        AssociatedObject.MouseLeftButtonDown += (sender, e) =>
        {
            _isMouseCaptured = true;
        };

        AssociatedObject.MouseLeftButtonUp += (sender, e) =>
        {
            _isMouseCaptured = false;
        };

        AssociatedObject.MouseMove += (sender, e) =>
        {
            if (_isMouseCaptured)
            {
                if (_parent == null)
                {
                    _parent = VisualTreeHelper.GetParent(AssociatedObject);
                    while (_parent.GetType() != typeof(Canvas))
                        _parent = VisualTreeHelper.GetParent(_parent);
                }
                var pointOnCanvas = e.GetPosition((Canvas)_parent);
                Canvas.SetTop(AssociatedObject, pointOnCanvas.Y);
                Canvas.SetLeft(AssociatedObject, pointOnCanvas.X);
            }
        };
    }

Если я использую экземпляр MyControl отдельно на Canvas, он работает, но если в ItemsControl есть коллекция MyControls, они не перемещаются на MouseMove

В WPF я бы использовал ItemContainerStyle, но в SL он недоступен:

        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Left" Value="{Binding Left}"/>
                <Setter Property="Canvas.Top" Value="{Binding Top}"/>
            </Style>
        </ItemsControl.ItemContainerStyle>

1 Ответ

1 голос
/ 17 декабря 2011

Когда вы используете ItemsControl, каждый сгенерированный элемент обернут в ContentPresenter. Визуальное дерево выглядит примерно так:

System.Windows.Controls.ItemsControl
  System.Windows.Controls.ItemsPresenter
    System.Windows.Controls.Canvas
      System.Windows.Controls.ContentPresenter
        DragControlBehaviorTest.MyControl
          ...

(DragControlBehaviorTest - это название проекта, который я создал, чтобы опробовать ваш код.)

Присоединенные свойства Canvas.Left и Canvas.Top работают только для прямых потомков Canvas. Если вы поместите MyControl непосредственно в Canvas, тогда ваш MyControl будет дочерним по отношению к Canvas, поэтому настройки Canvas.Left и Canvas.Top будут работать. Однако, если вы используете ItemsControl для генерации MyControl с, между Canvas и каждым из ваших MyControl с будет ContentPresenter. Вам необходимо установить свойства Canvas.Left и Canvas.Top для этих ContentPresenters.

У вас есть цикл, который запускается от AssociatedObject вверх по визуальному дереву, чтобы найти предка Canvas. Вы можете изменить это, чтобы найти непосредственного потомка холста, используя что-то вроде следующего:

            _immediateChild = AssociatedObject;
            _parent = VisualTreeHelper.GetParent(AssociatedObject);
            while (_parent.GetType() != typeof(Canvas))
            {
                _immediateChild = _parent;
                _parent = VisualTreeHelper.GetParent(_parent);
            }
...