So machen Sie ein Benutzersteuerelement wie ein Fenster auf dem Bildschirm ziehbar

So machen Sie ein Benutzersteuerelement wie ein Fenster auf dem Bildschirm ziehbar

Sie können einfach MouseDragElementBehavior.

verwenden

UPD Wichtiges zu MouseDragElementBehavior Verhalten:

Das MouseDragElementBehavior-Verhalten funktioniert nicht für Steuerelemente, die MouseClick-Ereignisse verarbeiten (z. B. Button-, TextBox- und ListBox-Steuerelemente). Wenn Sie die Möglichkeit benötigen, ein Steuerelement eines dieser Typen zu ziehen, machen Sie dieses Steuerelement zu einem untergeordneten Steuerelement, das gezogen werden kann (z. B. ein Rahmen). Anschließend können Sie das MouseDragElementBehavior-Verhalten auf das übergeordnete Element anwenden.

Sie können auch Ihr eigenes Ziehverhalten wie folgt implementieren:

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;
            }
        };
    }
}

Basierend auf den Informationen in der Antwort von @DmitryMartovoi habe ich eine Möglichkeit gefunden, dies zum Laufen zu bringen. Ich gebe Dmitry immer noch +1, da ich das ohne seinen Beitrag nicht hätte herausfinden können.

Ich habe eine TranslateTransform erstellt in meinem UserControl's Konstruktor und weist ihn seinem RenderTransform zu Eigenschaft:

RenderTransform = new TranslateTransform();

Im XAML habe ich den Border benannt Steuerelement, auf das der Benutzer klickt, um das gesamte Steuerelement zu ziehen:

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

    . . .
</Border>

Schließlich habe ich die verschiedenen Mouse-Event-Handler wie folgt modifiziert:

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;
    }
}

Das funktioniert wunderbar. Die gesamte UserControl und sein gesamter Inhalt bewegt sich reibungslos, wenn Sie Border ziehen , mit der Maus Schritt halten. Und die gesamten UserControl bewegt sich nicht, wenn Sie irgendwo anders auf seine Oberfläche klicken.

Nochmals vielen Dank an @DmitryMartovoi für den bereitgestellten Code.

BEARBEITEN:Ich bearbeite diese Antwort, weil der obige Code, obwohl er funktionierte, nicht perfekt war. Der Fehler besteht darin, dass das Steuerelement an seine ursprüngliche Position auf dem Bildschirm zurückspringt, wenn Sie auf den Titelleistenbereich geklickt haben und bevor Sie mit dem Ziehen begonnen haben. Das war ärgerlich und völlig falsch.

Der Ansatz, den ich mir ausgedacht hatte und der tatsächlich einwandfrei funktionierte, bestand darin, zuerst das Steuerelement in eine Canvas zu stecken . Es ist wichtig, dass das übergeordnete Element des Steuerelements ein Canvas ist oder der folgende Code funktioniert nicht. Ich habe auch aufgehört, den RenderTransform zu verwenden . Ich habe eine private Eigenschaft namens canvas hinzugefügt vom Typ Canvas . Ich habe einen Loaded hinzugefügt Ereignishandler an das Popup-Steuerelement, um einige wichtige Initialisierungen durchzuführen:

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." );
    }    
}

Nachdem dies alles erledigt ist, sind hier die modifizierten Mouse-Event-Handler:

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;
    }
}

Das Steuerelement bleibt dort, wo Sie es abgelegt haben, wenn Sie ein zweites Mal auf die Titelleiste klicken, um es zu verschieben, und es bewegt sich nur, wenn Sie auf die Titelleiste klicken. Das Klicken auf eine andere Stelle im Steuerelement bewirkt nichts, und das Ziehen ist reibungslos und reaktionsschnell.


http://www.codeproject.com/Tips/442276/Drag-and-Drop-WPF-ControlsDies ist die großartige Lösung, die ich nach viel Zeitaufwand erhalten habe. Obwohl das hier gezeigte Beispiel normale Steuerelemente sind, können Sie es nach einigen Änderungen auch für Benutzersteuerelemente verwenden.