2012-12-13 17 views
5

私のWPFアプリケーションには、ポップアップウィンドウのように見え、振る舞いますが、ウィンドウではないと思われるUserControlがあります。コントロールがWindowクラスから降下しないのは、サードパーティの仮想オンスクリーンキーボードが含まれているためで、そのコントロールは、クリックすると入力文字を送信するTextBoxコントロールと同じウィンドウ内になければならないためですそのボタン。キーボードコントロールが同じウィンドウにない場合は、TextBoxコントロールも表示されません。ウィンドウのように画面上でユーザーコントロールをドラッグ可能にする方法

私が抱えている問題は、ダイアログをドラッグするとパフォーマンスが非常に悪いことです。それは、マウスがドラッグ領域から出て、それがマウスに続いて停止するのに十分遅いです。私はより良い方法が必要です。

ここ制御のためのXAMLからの抜粋です:コントロールがそれを使用するウィンドウにCanvasの内側に配置されなければならないことを

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 < 0.0) mousePosition.X = 0.0; else if (mousePosition.X > canvas.ActualWidth) mousePosition.X = canvas.ActualWidth; 
      if (mousePosition.Y < 0.0) mousePosition.Y = 0.0; else if (mousePosition.Y > canvas.ActualHeight) mousePosition.Y = canvas.ActualHeight; 

      // Compute the new Left & 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 && 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 < 0.0) mousePosition.X = 0.0; else if (mousePosition.X > canvas.ActualWidth ) mousePosition.X = canvas.ActualWidth; 
      if (mousePosition.Y < 0.0) mousePosition.Y = 0.0; else if (mousePosition.Y > canvas.ActualHeight) mousePosition.Y = canvas.ActualHeight; 

      // Compute the new Left & 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; 
    } 

注:

<Grid Name="LayoutRoot"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="*" /> 
    </Grid.RowDefinitions> 
    <Border Background="{DynamicResource PopupBackground}" 
      BorderBrush="{DynamicResource PopupBorder}" 
      BorderThickness="5,5,5,0" 
      MouseLeftButtonDown="Grid_MouseLeftButtonDown" 
      MouseLeftButtonUp="Grid_MouseLeftButtonUp" 
      MouseMove="Grid_MouseMove"> 
    . . . 
    </Border> 
</Grid> 

ここでは、マウスイベントハンドラです。

DragMoveWindowクラスのメソッドであるため、このクラスはUserControlに由来しています。このコントロールのドラッグのパフォーマンスをどのように改善するのですか?私はWin32 APIに頼らなければならないのですか?

+0

http://stackoverflow.com/a/38830033/2507782 –

答えて

4

@ DmitryMartovoiの答えに情報に基づいて、私はこの作品を作るための方法が出ています。私はドミトリーに+1を与えているので、彼の貢献なしでこれを理解することはできなかったでしょう。 XAMLで

RenderTransform = new TranslateTransform(); 

、私は、ユーザーが全体のコントロールをドラッグすることでクリックBorderコントロールの名前:私は私のUserControl'sコンストラクタでTranslateTransformを作成し、そのRenderTransformプロパティに割り当てられていた何をしたか

次のよう

<Border Background="{DynamicResource PopupBackground}" 
     BorderBrush="{DynamicResource PopupBorder}" 
     BorderThickness="5,5,5,0" 
     MouseLeftButtonDown="Grid_MouseLeftButtonDown" 
     MouseLeftButtonUp="Grid_MouseLeftButtonUp" 
     MouseMove="Grid_MouseMove" 
     Name="TitleBorder"> 

    . . . 
</Border> 

最後に、私は、様々なマウスイベントハンドラを修飾:

private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { 
    CurrentMousePosition = e.GetPosition(Parent as Window); 
    TitleBorder.CaptureMouse(); 
} 

private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { 
    if (TitleBorder.IsMouseCaptured) { 
     TitleBorder.ReleaseMouseCapture(); 
    } 
} 

private void Grid_MouseMove(object sender, MouseEventArgs e) { 
    Vector diff = e.GetPosition(Parent as Window) - CurrentMousePosition; 
    if (TitleBorder.IsMouseCaptured) { 
     (RenderTransform as TranslateTransform).X = diff.X; 
     (RenderTransform as TranslateTransform).Y = diff.Y; 
    } 
} 

これは美しく機能します。Borderをドラッグすると、UserControl全体とそのすべてのコンテンツがスムーズに移動し、マウスに追いつきます。その表面の他の場所をクリックすると、UserControl全体が移動しません。

@DmitryMartovoiにも彼が提供したコードをありがとう。

編集:上記のコードは機能していたが完璧ではなかったので、この回答を編集しています。その欠点は、タイトルバー領域をクリックしたときとドラッグを開始する前に、コントロールが画面上の元の位置にポップバックすることです。これは迷惑で完全に間違っていた。

私が思いついたアプローチは、実際には最初にコントロールをCanvasに入れて完全に機能しました。コントロールの親がCanvasであるか、次のコードが機能しないことが重要です。私はまたRenderTransformの使用をやめました。 Canvascanvasというプライベートプロパティを追加しました。私はいくつかの重要な初期化を行うにポップアップコントロールにLoadedイベントハンドラを追加しました:あなたが落とし

private void TitleBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { 
    StartMousePosition = e.GetPosition(canvas); 
    TitleBorder.CaptureMouse(); 
} 

private void TitleBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { 
    if (TitleBorder.IsMouseCaptured) { 
     Point mousePosition = e.GetPosition(canvas); 
     Canvas.SetLeft(this, Canvas.GetLeft(this) + mousePosition.X - StartMousePosition.X); 
     Canvas.SetTop (this, Canvas.GetTop (this) + mousePosition.Y - StartMousePosition.Y); 
     canvas.ReleaseMouseCapture(); 
    } 
} 

private void TitleBorder_MouseMove(object sender, MouseEventArgs e) { 
    if (TitleBorder.IsMouseCaptured && e.LeftButton == MouseButtonState.Pressed) { 
     Point mousePosition = e.GetPosition(canvas); 

     // Compute the new Left & Top coordinates of the control 
     Canvas.SetLeft(this, Canvas.GetLeft(this) + mousePosition.X - StartMousePosition.X); 
     Canvas.SetTop (this, Canvas.GetTop (this) + mousePosition.Y - StartMousePosition.Y); 
     StartMousePosition = mousePosition; 
    } 
} 

制御滞在:行ってこのすべてで

private void KeyboardPopup_Loaded(object sender, RoutedEventArgs e) { 
    canvas = Parent as Canvas; 
    if (canvas == null) { 
     throw new InvalidCastException("The parent of a KeyboardPopup control must be a Canvas."); 
    }  
} 

を、ここで改変マウスイベントハンドラは、タイトルバーをクリックすると2回目に移動し、タイトルバーをクリックすると移動します。コントロール内の他の場所をクリックすると何も行われず、ドラッグはスムーズで反応的です。

5

MouseDragElementBehaviorをそのまま使用できます。

UPD 重要なものについてMouseDragElementBehavior行動:

MouseDragElementBehaviorの動作が(例えば、ボタン、テキストボックス、およびリストボックスコントロール)MouseClickとイベントを処理する任意のコントロールのために動作しません。これらのタイプのコントロールをドラッグする機能が必要な場合は、そのコントロールをドラッグできるコントロールの子(境界線など)にします。次に、親要素にMouseDragElementBehaviorビヘイビアを適用できます。

あなたはまた、次のように独自のドラッグ動作を実装できます。

public class DragBehavior : Behavior<UIElement> 
{ 
    private Point elementStartPosition; 
    private Point mouseStartPosition; 
    private TranslateTransform transform = new TranslateTransform(); 

    protected override void OnAttached() 
    { 
     Window parent = Application.Current.MainWindow; 
     AssociatedObject.RenderTransform = transform; 

     AssociatedObject.MouseLeftButtonDown += (sender, e) => 
     { 
      elementStartPosition = AssociatedObject.TranslatePoint(new Point(), parent); 
      mouseStartPosition = e.GetPosition(parent); 
      AssociatedObject.CaptureMouse(); 
     }; 

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

     AssociatedObject.MouseMove += (sender, e) => 
     { 
      Vector diff = e.GetPosition(parent) - mouseStartPosition; 
      if (AssociatedObject.IsMouseCaptured) 
      { 
       transform.X = diff.X; 
       transform.Y = diff.Y; 
      } 
     }; 
    } 
} 
+1

これは機能しますが、問題があります。最初は、&その子にビヘイビアを追加する要素にのみ適用されます。最初は、コントロールの "タイトルバー"の背景である 'Border'に振る舞いを追加しました。 'Border'だけがドラッグ可能で、残りのコントロールはそのまま残っていました。 'UserControl'自体や、すべてを保持する' Grid'のような、より高いものに振る舞いを適用すると、バックグラウンドやキーを構成するボタンを含め、何かをドラッグすると振る舞いが機能します。これも受け入れられません。 –

+1

ユーザーがテンプレート内の背景や他のコントロールをドラッグすることなくドラッグ全体をコントロールできるようにする方法はありますか? –

+1

MouseClickイベントを処理するコントロールを直接ドラッグすることはできません。 updを参照してください。 –

1

http://www.codeproject.com/Tips/442276/Drag-and-Drop-WPF-Controls これは私が多くの時間を費やして得た素晴らしいソリューションです。ここに示されている例は通常のコントロールですが、いくつかの変更の後でユーザーコントロールのためにも機能させることができます。

関連する問題