WPF – перетаскивание объекта внутри Grid (Drag inside Grid)


Столкнулся с несколько проблемной задачкой по организации перетаскивания объекта внутри grid’а – внутри canvas’а в гугле масса примеров, внутри грида – ноль.

Впринципе все довольно просто, достаточно взять стандартную функцию подходящую для canvas и немного переделать ее для изменения свойства margin вместо указания canvas.top/left, более того так получается даже понятнее и проще. Вот что нам нужно написать в XAML’е:

<Grid Name="parentGrid" SizeChanged="parentGrid_SizeChanged">
    <Canvas Name="mainGrid" SizeChanged="mainGrid_SizeChanged">
        <Image Name="planImg" Stretch="Fill" />
        <Thumb Visibility="Hidden" Cursor="Hand" Opacity="0" Margin="0,0,0,0" Name="thumb1" DragDelta="thumb1_DragDelta" DragStarted="thumb1_DragStarted" DragCompleted="thumb1_DragCompleted"></Thumb>
    </Canvas>
</Grid>

  • parentGrid – grid внутри которого хотим двигать элемент
  • planImg – элемент который хотим двигать, подходит любой элемент внутри нужного нам grid
  • thumb1 – это собственно элемент, которым можно легко и непринужденно двигать объектами – смысл в том что у него есть event DragDelta который запускается когда над элементом зажата левая кнопка мышки и курсор изменил свое положение (т.е. произошло перетаскивание). Событие генерирует аргумент DragDeltaEventArgs в котором передает два нужных нам параметра – HorizontalChange и VerticalChange
  • thumb1_DragDelta – необходимый нам event, который запускается в процессе перемещения thumb’а
  • thumb1_DragStarted – event запускающийся при начале перемещения
  • thumb1_DragCompleted – соответственно event запускающийся когда перемещение завершено (по факту отпускания левой кнопки мыши)

Теперь переходим к коду:

private void thumb1_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
{
    thumb1.DataContext = planImg;
}

private void thumb1_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
    (thumb1.DataContext as Image).Margin = new Thickness((thumb1.DataContext as Image).Margin.Left + e.HorizontalChange, (thumb1.DataContext as Image).Margin.Top + e.VerticalChange, (thumb1.DataContext as Image).Margin.Right — e.HorizontalChange, (thumb1.DataContext as Image).Margin.Bottom — e.VerticalChange);
    thumb1.Margin = new Thickness(thumb1.Margin.Left + e.HorizontalChange, thumb1.Margin.Top + e.VerticalChange, thumb1.Margin.Right — e.HorizontalChange, thumb1.Margin.Bottom — e.VerticalChange);
}

private void thumb1_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
{
}

Разберем по кускам:

  • Вначале мы должны задать DataContext для нашего thumb – по сути мы указываем каким элементом мы хотим двигать. Если мы хотим двигать сразу несколькими элементами то можно либо объеденить их в один общий контейнер (например в Canvas) либо немного изменить функцию dragDelta и сделать прямое обращение к нужным нам элементам (т.е. использовать вместо (thumb1.DataContext as Image) имя нужного элемента и расплодив первую строку функции в зависимости от кол-ва элементов) Обращение через DataContext я использую т.к. в моем проекте thumb управляет перемещением произвольного элемента среди произвольного количества кастомных компонентов – мне так проще делать привязку нежели отлавливать конкретный элемент в дереве.
  • Едем дальше – в самой функции DragDelta мы видим две строки – первая строка изменяет свойство Margin нашего управляемого компонента. Если вы перетаскиваете не картинку а например Canvas то логично что вам необходимо изменить as Image на as Canvas. Смысл измений Margin довольно прост – мы берем текущие Margin.Left, Top и т.п. и добавляем (или соотв. вычитаем) к ним значения аргументов HorizontalChange и VerticalChange т.е. собственно текущие дельты перемещения курсора
  • Вторая строка этой функции необходима для перемещения самого thumb – самостоятельно он с курсором не перемещается, это кажется не очень логичным, но я допускаю что в ряде случаев этому есть применение (например классический drag-and-drop без “просмотра содержимого окна при перетаскивании”)
  • Функцию DragCompleted можно оставить пустой – для непосредственного перемещения компонента по экрану она не нужна.

Вот

Все довольно просто на самом деле )

Запись опубликована в рубрике Без рубрики. Добавьте в закладки постоянную ссылку.

2 отзыва на “WPF – перетаскивание объекта внутри Grid (Drag inside Grid)

  1. анон:

    нечитабельная вёрстка текста

  2. wardeda:

    Благодарствую. Весьма помогло

Оставьте комментарий