title: WPF Drag Adorner fix movement and show feedback in Adorner
body: <p>I'm trying to build Inventory like interface for project that I'm creating.
  Idea is to have list of images that can be dragged to players as shown below:</p>
  
  <p><a href="https://i.stack.imgur.com/T5hUw.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/T5hUw.png" alt="enter image description here"></a></p>
  
  <p>Images are loaded from directory and displayed inside ListView, list of players is displayed in ListBox.</p>
  
  <p>My XAML looks like this:</p>
  
  <pre><code>&lt;Window x:Class="DynamicImagesDrag.MainWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:dynamicImagesDrag="clr-namespace:DynamicImagesDrag"
          Title="MainWindow"
          Height="405"
          Width="719.162"
          DataContext="{Binding RelativeSource={RelativeSource Self}}"&gt;
      &lt;Window.Resources&gt;
          &lt;dynamicImagesDrag:StringToImageConverter x:Key="StringToImageConverter" /&gt;
      &lt;/Window.Resources&gt;
      &lt;Grid&gt;
          &lt;ListView Name="MyList"
                    ItemsSource="{Binding Images}"
                    PreviewMouseLeftButtonDown="UIElement_OnPreviewMouseLeftButtonDown"
                    PreviewMouseMove="UIElement_OnPreviewMouseMove"
                    ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                    VerticalAlignment="Stretch"
                    HorizontalAlignment="Left"
                    Margin="10" Width="250"&gt;
              &lt;ListView.ItemsPanel&gt;
                  &lt;ItemsPanelTemplate&gt;
                      &lt;WrapPanel /&gt;
                  &lt;/ItemsPanelTemplate&gt;
              &lt;/ListView.ItemsPanel&gt;
  
              &lt;ListView.ItemContainerStyle&gt;
                  &lt;Style TargetType="ListViewItem"&gt;
                      &lt;Setter Property="Template"&gt;
                          &lt;Setter.Value&gt;
                              &lt;ControlTemplate TargetType="ListViewItem"&gt;
                                  &lt;ContentPresenter/&gt;
                              &lt;/ControlTemplate&gt;
                          &lt;/Setter.Value&gt;
                      &lt;/Setter&gt;
                  &lt;/Style&gt;
              &lt;/ListView.ItemContainerStyle&gt;
  
              &lt;ListView.ItemTemplate&gt;
                  &lt;DataTemplate&gt;
                      &lt;DockPanel Width="50" Height="50"&gt;
                          &lt;DockPanel.Background&gt;
                              &lt;ImageBrush ImageSource="BG1.png"/&gt;
                          &lt;/DockPanel.Background&gt;
                          &lt;Image Source="{Binding Path, Converter={StaticResource StringToImageConverter} }"
                                 Height="32"
                                 Width="32" /&gt;
                      &lt;/DockPanel&gt;
                  &lt;/DataTemplate&gt;
              &lt;/ListView.ItemTemplate&gt;
          &lt;/ListView&gt;
          &lt;ListBox ItemsSource="{Binding People}" HorizontalAlignment="Right" HorizontalContentAlignment="Stretch" Margin="10" VerticalAlignment="Stretch"
                   Width="200"&gt;
              &lt;ListBox.ItemTemplate&gt;
                  &lt;DataTemplate&gt;
                      &lt;StackPanel Orientation="Vertical" AllowDrop="True" PreviewDrop="UIElement_OnPreviewDrop"&gt;
                          &lt;TextBlock Text="{Binding Name}" FontWeight="Bold" /&gt;
                          &lt;ProgressBar Height="20" Value="{Binding Points}" Margin="0" /&gt;
                      &lt;/StackPanel&gt;
                  &lt;/DataTemplate&gt;
              &lt;/ListBox.ItemTemplate&gt;
          &lt;/ListBox&gt;
      &lt;/Grid&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>Code behind:</p>
  
  <pre><code>using System;
  using System.Collections.ObjectModel;
  using System.ComponentModel;
  using System.Diagnostics;
  using System.Globalization;
  using System.IO;
  using System.Linq;
  using System.Reflection;
  using System.Runtime.CompilerServices;
  using System.Runtime.InteropServices;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  
  namespace DynamicImagesDrag
  {
      /// &lt;summary&gt;
      /// Interaction logic for MainWindow.xaml
      /// &lt;/summary&gt;
      public partial class MainWindow
      {
          private readonly ObservableCollection&lt;MyImage&gt; _images = new ObservableCollection&lt;MyImage&gt;();
  
          public ObservableCollection&lt;MyImage&gt; Images
          {
              get { return _images; }
          }
  
          private readonly ObservableCollection&lt;Person&gt; _people = new ObservableCollection&lt;Person&gt;();
  
          public ObservableCollection&lt;Person&gt; People { get { return _people; } }
  
  
          public MainWindow()
          {
              InitializeComponent();
  
              _people.Add(new Person() { Name = "Person1", Points = 10 });
              _people.Add(new Person() { Name = "Person2", Points = 0 });
              _people.Add(new Person() { Name = "Person3", Points = 40 });
  
              string appPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
              if (appPath != null)
              {
                  string imagePath = Path.Combine(appPath, "Images");
                  if (Directory.Exists(imagePath))
                  {
                      var images = Directory
                          .EnumerateFiles(imagePath)
                          .Where(file =&gt; file.ToLower().EndsWith("jpg") || file.ToLower().EndsWith("png"))
                          .ToList();
  
                      foreach (string image in images)
                      {
                          _images.Add(new MyImage
                          {
                              Name = Path.GetFileName(image),
                              Path = image,
                              Points = Convert.ToInt32(Path.GetFileNameWithoutExtension(image))
                          });
                      }
                  }
              }
          }
  
          [DllImport("user32.dll")]
          [return: MarshalAs(UnmanagedType.Bool)]
          internal static extern bool GetCursorPos(ref Win32Point pt);
  
          [StructLayout(LayoutKind.Sequential)]
          internal struct Win32Point
          {
              public Int32 X;
              public Int32 Y;
          };
  
          public static Point GetMousePosition()
          {
              Win32Point w32Mouse = new Win32Point();
              GetCursorPos(ref w32Mouse);
              return new Point(w32Mouse.X, w32Mouse.Y);
          }
  
  
          private void UIElement_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
          {
              _startPoint = e.GetPosition(null);
          }
  
          #region Field and Properties
  
          private bool _dragHasLeftScope;
          private Point _startPoint;
          public bool IsDragging { get; set; }
  
          DragAdorner _adorner;
          AdornerLayer _layer;
          public FrameworkElement DragScope { get; set; }
  
          #endregion // Field and Properties
  
  
  
          private void UIElement_OnPreviewMouseMove(object sender, MouseEventArgs e)
          {
              // Ensure that the user does not drag by accident
              if (e.LeftButton == MouseButtonState.Pressed &amp;&amp; !IsDragging)
              {
                  Point position = e.GetPosition(null);
  
                  if (Math.Abs(position.X - _startPoint.X) &gt; SystemParameters.MinimumHorizontalDragDistance ||
                      Math.Abs(position.Y - _startPoint.Y) &gt; SystemParameters.MinimumVerticalDragDistance)
                  {
                      StartDragInProcAdorner(e);
                  }
              }
          }
  
          void DragScope_DragLeave(object sender, DragEventArgs e)
          {
              if (e.OriginalSource == DragScope)
              {
                  Point p = e.GetPosition(DragScope);
                  Rect r = VisualTreeHelper.GetContentBounds(DragScope);
                  if (!r.Contains(p))
                  {
                      _dragHasLeftScope = true;
                      e.Handled = true;
                  }
              }
          }
  
          void Window1_DragOver(object sender, DragEventArgs args)
          {
              if (_adorner == null) return;
              _adorner.LeftOffset = args.GetPosition(DragScope).X /* - _startPoint.X */ ;
              _adorner.TopOffset = args.GetPosition(DragScope).Y /* - _startPoint.Y */ ;
          }
  
          void DragScope_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
          {
              if (_dragHasLeftScope)
              {
                  e.Action = DragAction.Cancel;
                  e.Handled = true;
              }
          }
  
          private void StartDragInProcAdorner(MouseEventArgs e)
          {
              DragScope = Application.Current.MainWindow.Content as FrameworkElement;
  
              bool previousDrop = DragScope.AllowDrop;
              DragScope.AllowDrop = true;
              try
              {
                  DragEventHandler draghandler = Window1_DragOver;
                  DragScope.PreviewDragOver += draghandler;
                  DragEventHandler dragleavehandler = DragScope_DragLeave;
                  DragScope.DragLeave += dragleavehandler;
                  QueryContinueDragEventHandler queryhandler = DragScope_QueryContinueDrag;
                  DragScope.QueryContinueDrag += queryhandler;
  
                  DragScope.GiveFeedback+=DragScope_GiveFeedback;
  
                  FrameworkElement dr = MyList.ItemContainerGenerator.ContainerFromItem(MyList.SelectedItem) as FrameworkElement;
  
                  if (dr == null)
                      return;
                  _adorner = new DragAdorner(DragScope, dr, true, 0.5);
                  _layer = AdornerLayer.GetAdornerLayer(DragScope);
                  _layer.Add(_adorner);
  
  
                  IsDragging = true;
                  _dragHasLeftScope = false;
  
                  DataObject data = new DataObject(MyList.SelectedItem as MyImage);
                  DragDropEffects de = DragDrop.DoDragDrop(MyList, data, DragDropEffects.Move);
  
                  DragScope.AllowDrop = previousDrop;
                  AdornerLayer.GetAdornerLayer(DragScope).Remove(_adorner);
                  _adorner = null;
  
                  DragScope.DragLeave -= dragleavehandler;
                  DragScope.QueryContinueDrag -= queryhandler;
                  DragScope.PreviewDragOver -= draghandler;
  
                  IsDragging = false;
              }
              catch
              {
                  DragScope.AllowDrop = previousDrop;
                  AdornerLayer.GetAdornerLayer(DragScope).Remove(_adorner);
                  _adorner = null;
                  IsDragging = false;
  
              }
          }
  
          private void DragScope_GiveFeedback(object sender, GiveFeedbackEventArgs e)
          {
  
  
          }
  
          private void UIElement_OnPreviewDrop(object sender, DragEventArgs e)
          {
              var stackPanel = sender as StackPanel;
              if (stackPanel == null) return;
              var student = stackPanel.DataContext as Person;
  
              MyImage myImage = e.Data.GetData(typeof(MyImage)) as MyImage;
              if (student != null) student.Points += myImage.Points;
          }
      }
  
      public class StringToImageConverter : IValueConverter
      {
          public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
          {
              try
              {
                  return new BitmapImage(new Uri((string)value));
              }
              catch
              {
                  return new BitmapImage();
              }
          }
  
          public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
          {
              throw new NotImplementedException();
          }
      }
  
      public class Person : INotifyPropertyChanged
      {
          private string _name;
          private int _points;
  
          public string Name
          {
              get { return _name; }
              set
              {
                  if (value == _name) return;
                  _name = value;
                  OnPropertyChanged();
              }
          }
  
          public int Points
          {
              get { return _points; }
              set
              {
                  if (value == _points) return;
                  _points = value;
                  if (_points &gt;= 100)
                  {
                      _points -= 100;
                      Debug.WriteLine("100!");
                  }
                  OnPropertyChanged();
              }
          }
  
          public event PropertyChangedEventHandler PropertyChanged;
  
          protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
          {
              var handler = PropertyChanged;
              if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
          }
      }
  
      public class MyImage
      {
          public string Path { get; set; }
          public string Name { get; set; }
  
          public int Points { get; set; }
      }
  }
  </code></pre>
  
  <p>and DragAdorner (taken from <a href="http://www.infragistics.com/community/blogs/alex_fidanov/archive/2009/07/28/drag-amp-drop-with-datapresenter-family-controls.aspx" rel="nofollow noreferrer">http://www.infragistics.com/community/blogs/alex_fidanov/archive/2009/07/28/drag-amp-drop-with-datapresenter-family-controls.aspx</a>)</p>
  
  <pre><code>class DragAdorner : Adorner
  {
      public DragAdorner(UIElement owner) : base(owner) { }
  
      public DragAdorner(UIElement owner, UIElement adornElement, bool useVisualBrush, double opacity)
          : base(owner)
      {
          _owner = owner;
          VisualBrush _brush = new VisualBrush
          {
              Opacity = opacity,
              Visual = adornElement
          };
  
          DropShadowEffect dropShadowEffect = new DropShadowEffect
          {
              Color = Colors.Black,
              BlurRadius = 15,
              Opacity = opacity
          };
  
          Rectangle r = new Rectangle
          {
              RadiusX = 3,
              RadiusY = 3,
              Fill = _brush,
              Effect = dropShadowEffect,
              Width = adornElement.DesiredSize.Width,
              Height = adornElement.DesiredSize.Height
          };
  
  
          XCenter = adornElement.DesiredSize.Width / 2;
          YCenter = adornElement.DesiredSize.Height / 2;
  
          _child = r;
      }
  
      private void UpdatePosition()
      {
          AdornerLayer adorner = (AdornerLayer)Parent;
          if (adorner != null)
          {
              adorner.Update(AdornedElement);
          }
      }
  
      #region Overrides
  
      protected override Visual GetVisualChild(int index)
      {
          return _child;
      }
      protected override int VisualChildrenCount
      {
          get
          {
              return 1;
          }
      }
      protected override Size MeasureOverride(Size finalSize)
      {
          _child.Measure(finalSize);
          return _child.DesiredSize;
      }
      protected override Size ArrangeOverride(Size finalSize)
      {
  
          _child.Arrange(new Rect(_child.DesiredSize));
          return finalSize;
      }
      public override GeneralTransform GetDesiredTransform(GeneralTransform transform)
      {
          GeneralTransformGroup result = new GeneralTransformGroup();
  
          result.Children.Add(base.GetDesiredTransform(transform));
          result.Children.Add(new TranslateTransform(_leftOffset, _topOffset));
          return result;
      }
  
      #endregion
  
      #region Field &amp; Properties
  
      public double scale = 1.0;
      protected UIElement _child;
      protected VisualBrush _brush;
      protected UIElement _owner;
      protected double XCenter;
      protected double YCenter;
      private double _leftOffset;
      public double LeftOffset
      {
          get { return _leftOffset; }
          set
          {
              _leftOffset = value - XCenter;
              UpdatePosition();
          }
      }
      private double _topOffset;
      public double TopOffset
      {
          get { return _topOffset; }
          set
          {
              _topOffset = value - YCenter;
  
              UpdatePosition();
          }
      }
  
      #endregion
  }
  </code></pre>
  
  <p>Drag works almost fine:</p>
  
  <p><a href="https://i.stack.imgur.com/O77PT.gif" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/O77PT.gif" alt="enter image description here"></a></p>
  
  <p>except adorner is visible only in source list and target list, it isn't displayed during whole drag.</p>
  
  <p>My questions are:</p>
  
  <ul>
  <li>How can I fix drag and drop to see adorner whole time? </li>
  <li>How can I display image instead selectedItem inside adorner? Right now inside adorner is that brown background, I'd like to get only transparent image.</li>
  <li>How can I show if dragtarget is correct inside adorner instead of changing cursor? I'd like to change opacity of adorner if target is correct.</li>
  <li>I'd like to get drag and drop working with touch events, @KOTIX suggested using Gong WPF dragdrop, will it work fine on touch enabled screens?</li>
  <li>Currently I'm setting <code>AllowDrop</code> on StackPanel inside ListBox ItemTemplate, should it stay there or maybe I should set in on ListBox?</li>
  </ul>
  
  <p>I've searched over internet (including SO) for solution, but I couldn't find anything that fits my needs.</p>
  
  <p>I found some great articles:<br/>
  <a href="http://www.codeproject.com/Articles/37161/WPF-Drag-and-Drop-Smorgasbord" rel="nofollow noreferrer">http://www.codeproject.com/Articles/37161/WPF-Drag-and-Drop-Smorgasbord</a><br/>
  <a href="http://www.zagstudio.com/blog/488#.VgHPyxHtmkp" rel="nofollow noreferrer">http://www.zagstudio.com/blog/488#.VgHPyxHtmkp</a><br/>
  <a href="http://nonocast.cn/adorner-in-wpf-part-5-drag-and-drop/" rel="nofollow noreferrer">http://nonocast.cn/adorner-in-wpf-part-5-drag-and-drop/</a><br/>
  <a href="https://blogs.claritycon.com/blog/2009/03/generic-wpf-drag-and-drop-adorner/" rel="nofollow noreferrer">https://blogs.claritycon.com/blog/2009/03/generic-wpf-drag-and-drop-adorner/</a><br/></p>
  
  <p>Last one was very interesting, but I wasn't able to modify it in a way to add points to players instead of moving items. In my case I want items on left to stay, I just want to update list on right based on dragged item.</p>