title: Dragging images with transparent background in Silverlight
body: <p>I have a Canvas (Puzzle) and a list of child png images (PuzzleParts) with transparent background. I need to drag these image only if mouse over non-transparent part of image. So, my implementation looks like this:</p>
  
  <pre><code>    public class Puzzle : Canvas
      {
          public Puzzle()
          {
              Background = new SolidColorBrush(Colors.Transparent);
              MouseLeftButtonDown += Puzzle_MouseLeftButtonDown;
          }
  
          public void Load(PuzzleSettings settings)
          {
              foreach (var child in Children)
              {
                  //child.MouseLeftButtonDown -= OnMouseLeftButtonDown;
                  child.MouseLeftButtonUp -= OnMouseLeftButtonUp;
                  child.MouseMove -= OnMouseMove;
              }
              Children.Clear();
  
              foreach (var part in settings.Parts)
              {
                  var puzzlePart = new PuzzlePart(part);
                  //puzzlePart.MouseLeftButtonDown += OnMouseLeftButtonDown;
                  puzzlePart.MouseLeftButtonUp += OnMouseLeftButtonUp;
                  puzzlePart.MouseMove += OnMouseMove;
  
                  Children.Add(puzzlePart);
              }
          }
  
          /// Finds all PuzzleParts under mouse pointer and first of them with non-
          /// transparent pixel (dragging PuzzlePart)
          private void Puzzle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
          {
              var elements = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(null), this);
  
              foreach (var element in elements)
              {
  
                  if (!(element is PuzzlePart))
                      continue;
  
                  var part = element as PuzzlePart;
  
                  if (!IsTransparentPixel(part, e.GetPosition(part)))
                  {
                      OnMouseLeftButtonDown(part, e);
                      break;
                  }
              }
          }
  
          /// Checks if specific pixel of PuzzlePart is transparent
          private bool IsTransparentPixel(PuzzlePart part, Point point)
          {
              var uri = new Uri(part.Settings.ImagePath, UriKind.Relative);
              var bitmapImage = new BitmapImage {CreateOptions = BitmapCreateOptions.None, UriSource = uri};
              var writableBitmap = new WriteableBitmap(bitmapImage);
  
              // check bounds
              if (point.X &lt; 0.0 || point.X &gt; writableBitmap.PixelWidth - 1 ||
                  point.Y &lt; 0.0 || point.Y &gt; writableBitmap.PixelHeight - 1)
                  return false;
  
              var row = (int)Math.Floor(point.Y);
              var col = (int)Math.Floor(point.X);
  
              int pixel = writableBitmap.Pixels[row * writableBitmap.PixelWidth + col];
              byte[] pixelBytes = BitConverter.GetBytes(pixel);
  
              if (pixelBytes[0] == 0x00)
                  return true;
  
              return false;
          }
  
          private bool _isDragging;
  
          private Point _lastPosition;
  
          private double _offsetX;
  
          private double _offsetY;
  
          private int _lastZIndex;
  
          #region Puzzle part dragging
  
          /// Performs PuzzlePart dragging
          private void OnMouseMove(object sender, MouseEventArgs e)
          {
              if (_isDragging)
              {
                  var puzzlePart = (PuzzlePart) sender;
  
                  Point p = e.GetPosition(this);
                  double x = p.X - _offsetX;
                  double y = p.Y - _offsetY;
  
                  var displacementX = puzzlePart.Settings.ControlPoint.Position.X - x;
                  var displacementY = puzzlePart.Settings.ControlPoint.Position.Y - y;
  
                  if (Math.Sqrt(displacementX * displacementX + displacementY * displacementY) &lt; _sensivity)
                  {
                      x = puzzlePart.Settings.ControlPoint.Position.X;
                      y = puzzlePart.Settings.ControlPoint.Position.Y;
                  }
  
                  // Set the new position for the puzzle part control.
                  puzzlePart.SetValue(LeftProperty, x);
                  puzzlePart.SetValue(TopProperty, y);
              }
          }
  
          /// Ends drag operation
          private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
          {
              var element = (UIElement)sender; 
  
              _isDragging = false;
              element.ReleaseMouseCapture();
              _lastPuzzlePart = (PuzzlePart) element;
          }
  
          /// Begins drag operation
          private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
          {
  
              var puzzlePart = (PuzzlePart) sender;
              puzzlePart.CaptureMouse();
              _isDragging = true;
              SetZIndex(puzzlePart, _lastZIndex++);
              _lastPosition = e.GetPosition(puzzlePart);
              _offsetX = _lastPosition.X;
              _offsetY = _lastPosition.Y;
          }
  
          #endregion
      }
  </code></pre>
  
  <p>It works good when the PuzzlePart is on top of the Canvas, but I have performance problem with dragging when the PuzzlePart is not on top and it need to find dragging image by inspecting mouse over pixels. I don't understand what problem is.
  My XAML code:</p>
  
  <pre><code>&lt;phone:PhoneApplicationPage
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
      xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:eim="clr-namespace:Microsoft.Expression.Interactivity.Media;assembly=Microsoft.Expression.Interactions"
      xmlns:Controls="clr-namespace:KidsABCPuzzle.Controls;assembly=KidsABCPuzzle.Controls"
      x:Class="KidsABCPuzzle.Views.PuzzleView"
      FontFamily="{StaticResource PhoneFontFamilyNormal}"
      FontSize="{StaticResource PhoneFontSizeNormal}"
      Foreground="{StaticResource PhoneForegroundBrush}"
      SupportedOrientations="Landscape" Orientation="Landscape"
      mc:Ignorable="d" d:DesignHeight="480" d:DesignWidth="800"
      shell:SystemTray.IsVisible="False"&gt;
      &lt;phone:PhoneApplicationPage.Resources&gt;
          &lt;Storyboard x:Name="LoadedStoryboard"&gt;
              &lt;DoubleAnimation Duration="0:0:1" To="0.6" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="border" d:IsOptimized="True"&gt;
                  &lt;DoubleAnimation.EasingFunction&gt;
                      &lt;CubicEase EasingMode="EaseOut"/&gt;
                  &lt;/DoubleAnimation.EasingFunction&gt;
              &lt;/DoubleAnimation&gt;
          &lt;/Storyboard&gt;
      &lt;/phone:PhoneApplicationPage.Resources&gt;
  
      &lt;Grid x:Name="LayoutRoot" Background="Transparent"&gt;
          &lt;Image Source="../Images/Level1.png"/&gt;
          &lt;Border x:Name="border" Background="White" Opacity="0.0"&gt;
              &lt;i:Interaction.Triggers&gt;
                  &lt;i:EventTrigger&gt;
                      &lt;eim:ControlStoryboardAction Storyboard="{StaticResource LoadedStoryboard}"/&gt;
                  &lt;/i:EventTrigger&gt;
              &lt;/i:Interaction.Triggers&gt;
          &lt;/Border&gt;
          &lt;Controls:Puzzle x:Name="puzzle"/&gt;
      &lt;/Grid&gt;
  &lt;/phone:PhoneApplicationPage&gt;
  </code></pre>
  
  <p>and PuzzlePart:</p>
  
  <pre><code>&lt;Style TargetType="Controls:PuzzlePart"&gt;
      &lt;Setter Property="Background" Value="Transparent"/&gt;
      &lt;Setter Property="Template"&gt;
          &lt;Setter.Value&gt;
              &lt;ControlTemplate TargetType="Controls:PuzzlePart"&gt;
                  &lt;Grid&gt;
                      &lt;Image x:Name="Image"/&gt;
                  &lt;/Grid&gt;
              &lt;/ControlTemplate&gt;
          &lt;/Setter.Value&gt;
      &lt;/Setter&gt;
  &lt;/Style&gt;
  
  
  
      /// &lt;summary&gt;
      /// Represents puzzle part
      /// &lt;/summary&gt;
      [TemplatePart(Name = "Image", Type = typeof(Image))]
      public class PuzzlePart : ContentControl
      {
          /// &lt;summary&gt;
          /// Image of puzzle part
          /// &lt;/summary&gt;
          public Image Image { get; private set; }
  
          public PuzzlePartSettings Settings { get; set; }
  
          /// &lt;summary&gt;
          /// Default constructor
          /// &lt;/summary&gt;
          /// &lt;param name="point"&gt; Intialization placement. &lt;/param&gt;
          public PuzzlePart(ControlPoint point)
          {
              DefaultStyleKey = typeof(PuzzlePart);
  
              Settings.ControlPoint = point;
          }
  
          public PuzzlePart(PuzzlePartSettings settings)
          {
              DefaultStyleKey = typeof (PuzzlePart);
  
              Settings = settings;
          }
  
          /// &lt;summary&gt;
          /// Applies default template
          /// &lt;/summary&gt;
          public override void  OnApplyTemplate()
          {
              base.OnApplyTemplate();
              Image = (Image)GetTemplateChild("Image");
  
              if (Settings != null 
                  &amp;&amp; !string.IsNullOrEmpty(Settings.ImagePath))
              {
                  Image.Source = new BitmapImage(new Uri(Settings.ImagePath, UriKind.Relative));
              }
          }
      }
  </code></pre>