c# tutorial Machen Sie das WPF-Fenster ziehbar, unabhängig davon, auf welches Element geklickt wurde




wpf tutorial deutsch pdf (7)

Meine Frage ist 2-fach, und ich hoffe, dass es einfachere Lösungen für beide gibt, die von WPF bereitgestellt werden, als die Standardlösungen von WinForms (die Christophe Geers zur Verfügung gestellt hat, bevor ich diese Klarstellung gemacht habe).

Erstens, gibt es eine Möglichkeit, Fenster ziehbar zu machen, ohne Mausklick- und Ziehereignisse zu erfassen und zu verarbeiten? Ich meine, das Fenster kann durch die Titelleiste gezogen werden, aber wenn ich ein Fenster so eingestellt habe, dass ich es nicht ziehen kann und es trotzdem ziehen kann, gibt es eine Möglichkeit, die Ereignisse irgendwie auf die Griffe der Titelleiste umzuleiten ?

Zweitens, gibt es eine Möglichkeit, einen Event-Handler auf alle Elemente im Fenster anzuwenden? Wie in, machen Sie das Fenster ziehbar, egal welches Element der Benutzer klickt + zieht. Offensichtlich, ohne den Handler manuell zu jedem einzelnen Element hinzuzufügen. Mach es einfach einmal irgendwo?


Manchmal haben wir keinen Zugriff auf Window , zB wenn wir DevExpress , ist nur ein UIElement verfügbar.

Schritt 1: Fügen Sie die angehängte Eigenschaft hinzu

Die Lösung ist:

  1. Hook in MouseMove Ereignisse;
  2. Durchsuchen Sie den visuellen Baum, bis wir das erste übergeordnete Window ;
  3. Rufen Sie .DragMove() auf unserem neu entdeckten Window .

Code:

using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace DXApplication1.AttachedProperty
{
    public class EnableDragHelper
    {
        public static readonly DependencyProperty EnableDragProperty = DependencyProperty.RegisterAttached(
            "EnableDrag",
            typeof (bool),
            typeof (EnableDragHelper),
            new PropertyMetadata(default(bool), OnLoaded));

        private static void OnLoaded(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
        {
            var uiElement = dependencyObject as UIElement;
            if (uiElement == null || (dependencyPropertyChangedEventArgs.NewValue is bool) == false)
            {
                return;
            }
            if ((bool)dependencyPropertyChangedEventArgs.NewValue  == true)
            {
                uiElement.MouseMove += UIElementOnMouseMove;
            }
            else
            {
                uiElement.MouseMove -= UIElementOnMouseMove;
            }

        }

        private static void UIElementOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
        {
            var uiElement = sender as UIElement;
            if (uiElement != null)
            {
                if (mouseEventArgs.LeftButton == MouseButtonState.Pressed)
                {
                    DependencyObject parent = uiElement;
                    int avoidInfiniteLoop = 0;
                    // Search up the visual tree to find the first parent window.
                    while ((parent is Window) == false)
                    {
                        parent = VisualTreeHelper.GetParent(parent);
                        avoidInfiniteLoop++;
                        if (avoidInfiniteLoop == 1000)
                        {
                            // Something is wrong - we could not find the parent window.
                            return;
                        }
                    }
                    var window = parent as Window;
                    window.DragMove();
                }
            }
        }

        public static void SetEnableDrag(DependencyObject element, bool value)
        {
            element.SetValue(EnableDragProperty, value);
        }

        public static bool GetEnableDrag(DependencyObject element)
        {
            return (bool)element.GetValue(EnableDragProperty);
        }
    }
}

Schritt 2: Fügen Sie die angehängte Eigenschaft zu einem beliebigen Element hinzu, damit es das Fenster ziehen kann

Der Benutzer kann das gesamte Fenster ziehen, indem er auf ein bestimmtes Element klickt, wenn wir diese angefügte Eigenschaft hinzufügen:

<Border local:EnableDragHelper.EnableDrag="True">
    <TextBlock Text="Click me to drag this entire window"/>
</Border>

Anhang A: Optionales erweitertes Beispiel

In diesem Beispiel von DevExpress ersetzen wir die Titelleiste eines DevExpress durch unser eigenes graues Rechteck und stellen dann sicher, dass das Fenster beim Ziehen und Ziehen des grauen Rechtecks ​​normal gezogen wird:

<dx:DXWindow x:Class="DXApplication1.MainWindow" Title="MainWindow" Height="464" Width="765" 
    xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking" 
    xmlns:local="clr-namespace:DXApplication1.AttachedProperty"
    xmlns:dxdove="http://schemas.devexpress.com/winfx/2008/xaml/docking/visualelements"
    xmlns:themeKeys="http://schemas.devexpress.com/winfx/2008/xaml/docking/themekeys">

    <dxdo:DockLayoutManager FloatingMode="Desktop">
        <dxdo:DockLayoutManager.FloatGroups>
            <dxdo:FloatGroup FloatLocation="0, 0" FloatSize="179,204" MaxHeight="300" MaxWidth="400" 
                             local:TopmostFloatingGroupHelper.IsTopmostFloatingGroup="True"                             
                             >
                <dxdo:LayoutPanel ShowBorder="True" ShowMaximizeButton="False" ShowCaption="False" ShowCaptionImage="True" 
                                  ShowControlBox="True" ShowExpandButton="True" ShowInDocumentSelector="True" Caption="TradePad General" 
                                  AllowDock="False" AllowHide="False" AllowDrag="True" AllowClose="False"
                                  >
                    <Grid Margin="0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Border Grid.Row="0" MinHeight="15" Background="#FF515151" Margin="0 0 0 0"
                                                                  local:EnableDragHelper.EnableDrag="True">
                            <TextBlock Margin="4" Text="General" FontWeight="Bold"/>
                        </Border>
                        <TextBlock Margin="5" Grid.Row="1" Text="Hello, world!" />
                    </Grid>
                </dxdo:LayoutPanel>
            </dxdo:FloatGroup>
        </dxdo:DockLayoutManager.FloatGroups>
    </dxdo:DockLayoutManager>
</dx:DXWindow>

Haftungsausschluss: Ich bin nicht mit DevExpress . Diese Technik funktioniert mit jedem Benutzerelement, einschließlich Standard-WPF oder Telerik (ein weiterer guter WPF-Bibliotheksanbieter).


Wenn das WPF-Formular ziehbar sein muss, egal wo es angeklickt wurde, ist die einfache Arbeit die Verwendung eines Delegates, um die DragMove () -Methode entweder beim Windows-Onload-Ereignis oder beim Grid-Load-Ereignis auszulösen

private void Grid_Loaded(object sender, RoutedEventArgs 
{
      this.MouseDown += delegate{DragMove();};
}

Sicher, wenden Sie das folgende MouseDown Ereignis Ihres Window

private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.ChangedButton == MouseButton.Left)
        this.DragMove();
}

Dadurch können Benutzer das Fenster ziehen, wenn sie auf ein Steuerelement klicken / ziehen, AUSSER für Steuerelemente, die das MouseDown-Ereignis essen ( e.Handled = true )

Sie können PreviewMouseDown anstelle von MouseDown , aber das MouseDown isst das Click Ereignis, sodass Ihr Fenster nicht mehr auf Ereignisse mit Linksklick reagiert. Wenn Sie das Formular wirklich von einem beliebigen Steuerelement aus klicken und ziehen PreviewMouseDown , könnten Sie PreviewMouseDown , einen Timer starten, um den MouseUp zu starten, und den Vorgang abbrechen, wenn das MouseUp Ereignis innerhalb von X Millisekunden MouseUp .


private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
    this.DragMove();
}

Wird in einigen Fällen eine Ausnahme ausgelöst (dh wenn Sie auf dem Fenster auch ein anklickbares Bild haben, das beim Anklicken ein Meldungsfeld öffnet. Wenn Sie das Meldungsfeld verlassen, erhalten Sie einen Fehler) Es ist sicherer zu verwenden

private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
            this.DragMove();
}

Sie sind also sicher, dass in diesem Moment die linke Taste gedrückt wird.


Die nützlichste Methode, sowohl für WPF und Windows Form, WPF Beispiel:

    [DllImport("user32.dll")]
    public static extern IntPtr SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);

    public static void StartDrag(Window window)
    {
        WindowInteropHelper helper = new WindowInteropHelper(window);
        SendMessage(helper.Handle, 161, 2, 0);
    }

Das ist alles nötig!

private void UiElement_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            if (this.WindowState == WindowState.Maximized) // In maximum window state case, window will return normal state and continue moving follow cursor
            {
                this.WindowState = WindowState.Normal;
                Application.Current.MainWindow.Top = 3;// 3 or any where you want to set window location affter return from maximum state
            }
            this.DragMove();
        }
    }

Sie können ein Formular per Drag & Drop ziehen, indem Sie auf eine beliebige Stelle im Formular klicken, nicht nur auf die Titelleiste. Dies ist praktisch, wenn Sie ein randloses Formular haben.

Dieser Artikel zu CodeProject demonstriert eine mögliche Lösung, um das zu implementieren:

http://www.codeproject.com/KB/cs/DraggableForm.aspx

Grundsätzlich wird ein Nachkomme vom Form-Typ erstellt, in dem die Ereignisse "Mouse Down", "Up" und "Move" behandelt werden.

  • Maustaste gedrückt: Position merken
  • Mausbewegung: neuen Standort speichern
  • Maus hoch: Positioniere das Formular an einem neuen Ort

Und hier ist eine ähnliche Lösung in einem Video-Tutorial erklärt:

http://www.youtube.com/watch?v=tJlY9aX73Vs

Ich würde nicht erlauben, das Formular zu ziehen, wenn ein Benutzer auf ein Steuerelement in diesem Formular klickt. Benutzer können unterschiedliche Ergebnisse erzielen, wenn sie auf verschiedene Steuerelemente klicken. Wenn sich mein Formular plötzlich bewegt, weil ich auf ein Listenfeld, eine Schaltfläche, ein Label usw. geklickt habe. das wäre verwirrend.





drag-and-drop