title: How to make a user control draggable on screen like a window
body: <p>My WPF application has a <code>UserControl</code> which is supposed to look and behave like a popup window, but it isn't a window.  The reason the control doesn't descend from the <code>Window</code> class is because it contains a third-party virtual on-screen keyboard, and that control has to be in the same window as the <code>TextBox</code> controls that it sends input characters to when you click on its buttons.  If the keyboard control is not in the same window, it can't even see the <code>TextBox</code> controls.</p>
  
  <p>The problem I'm having is performance is abysmal when dragging the dialog around.  It's sufficiently slow that the mouse comes off the drag area and it stops following the mouse.  I need a better way.</p>
  
  <p>Here's an excerpt from the xaml for the control:</p>
  
  <pre><code>&lt;Grid Name="LayoutRoot"&gt;
      &lt;Grid.RowDefinitions&gt;
          &lt;RowDefinition Height="Auto" /&gt;
          &lt;RowDefinition Height="*" /&gt;
      &lt;/Grid.RowDefinitions&gt;
      &lt;Border Background="{DynamicResource PopupBackground}"
              BorderBrush="{DynamicResource PopupBorder}"
              BorderThickness="5,5,5,0"
              MouseLeftButtonDown="Grid_MouseLeftButtonDown"
              MouseLeftButtonUp="Grid_MouseLeftButtonUp"
              MouseMove="Grid_MouseMove"&gt;
      . . .
      &lt;/Border&gt;
  &lt;/Grid&gt;
  </code></pre>
  
  <p>Here's the mouse event handlers:</p>
  
  <pre><code>    private void Grid_MouseLeftButtonDown( object sender, MouseButtonEventArgs e ) {
          Canvas canvas = Parent as Canvas;
          if ( canvas == null ) {
              throw new InvalidCastException( "The parent of a KeyboardPopup control must be a Canvas." );
          }
          DraggingControl = true;
          CurrentMousePosition = e.GetPosition( canvas );
          e.Handled = true;
      }
  
      private void Grid_MouseLeftButtonUp( object sender, MouseButtonEventArgs e ) {
          Canvas canvas = Parent as Canvas;
          if ( canvas == null ) {
              throw new InvalidCastException( "The parent of a KeyboardPopup control must be a Canvas." );
          }
  
          if ( DraggingControl ) {
              Point mousePosition = e.GetPosition( canvas );
  
              // Correct the mouse coordinates in case they go off the edges of the control
              if ( mousePosition.X &lt; 0.0 ) mousePosition.X = 0.0; else if ( mousePosition.X &gt; canvas.ActualWidth ) mousePosition.X = canvas.ActualWidth;
              if ( mousePosition.Y &lt; 0.0 ) mousePosition.Y = 0.0; else if ( mousePosition.Y &gt; canvas.ActualHeight ) mousePosition.Y = canvas.ActualHeight;
  
              // Compute the new Left &amp; Top coordinates of the control
              Canvas.SetLeft( this, Left += mousePosition.X - CurrentMousePosition.X );
              Canvas.SetTop( this, Top += mousePosition.Y - CurrentMousePosition.Y );
          }
          e.Handled = true;
      }
  
      private void Grid_MouseMove( object sender, MouseEventArgs e ) {
          Canvas canvas = Parent as Canvas;
          if ( canvas == null ) {
              // It is not.  Throw an exception
              throw new InvalidCastException( "The parent of a KeyboardPopup control must be a Canvas." );
          }
  
          if ( DraggingControl &amp;&amp; e.LeftButton == MouseButtonState.Pressed ) {
              Point mousePosition = e.GetPosition( canvas );
  
              // Correct the mouse coordinates in case they go off the edges of the control
              if ( mousePosition.X &lt; 0.0 ) mousePosition.X = 0.0; else if ( mousePosition.X &gt; canvas.ActualWidth  ) mousePosition.X = canvas.ActualWidth;
              if ( mousePosition.Y &lt; 0.0 ) mousePosition.Y = 0.0; else if ( mousePosition.Y &gt; canvas.ActualHeight ) mousePosition.Y = canvas.ActualHeight;
  
              // Compute the new Left &amp; Top coordinates of the control
              Canvas.SetLeft( this, Left += mousePosition.X - CurrentMousePosition.X );
              Canvas.SetTop ( this, Top  += mousePosition.Y - CurrentMousePosition.Y );
  
              CurrentMousePosition = mousePosition;
          }
          e.Handled = true;
      }
  </code></pre>
  
  <p>Note that the control must be placed inside a <code>Canvas</code> in the window that uses it.</p>
  
  <p>I can't use <code>DragMove</code> as it's a method of the <code>Window</code> class and this class descends from <code>UserControl</code>.  How do I improve the performance of this control's dragging?  Do I have to resort to Win32 APIs?</p>