it-swarm.it

Rendi trascinabile la finestra di WPF, indipendentemente dall'elemento su cui si fa clic

La mia domanda è di 2 volte, e spero che ci siano soluzioni più semplici entrambe fornite daWPFpiuttosto che le soluzioni standard di WinForms (che Christophe Geers ha fornito, prima che io abbia reso questo chiarimento).

Innanzitutto, esiste un modo per rendere Window trascinabile senza acquisire e elaborare il clic del mouse + trascinare gli eventi? Voglio dire che la finestra è trascinabile dalla barra del titolo, ma se imposto una finestra per non averne uno e voglio ancora poterlo trascinare, c'è un modo per reindirizzare gli eventi in qualche modo a qualsiasi cosa gestisca il trascinamento della barra del titolo ?

Secondo, c'è un modo per applicare un gestore di eventi a tutti gli elementi nella finestra? Come in, rendere trascinabile la finestra indipendentemente dall'elemento che l'utente fa clic + trascina. Ovviamente senza aggiungere manualmente il gestore, a ogni singolo elemento. Fallo una volta da qualche parte?

94
Alex K

Certo, applica il seguente evento MouseDown del tuo Window

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

Ciò consentirà agli utenti di trascinare la finestra quando fanno clic/trascinamento su qualsiasi controllo, ad eccezione dei controlli che utilizzano l'evento MouseDown (e.Handled = true)

È possibile utilizzare PreviewMouseDown anziché MouseDown, ma l'evento di trascinamento mangia l'evento Click, pertanto la finestra smette di rispondere agli eventi di clic del mouse sinistro. Se si desidera VERAMENTE essere in grado di fare clic e trascinare il modulo da qualsiasi controllo, è possibile utilizzare PreviewMouseDown, avviare un timer per iniziare l'operazione di trascinamento e annullare l'operazione se l'evento MouseUp si attiva entro X millisecondi.

239
Rachel

se il modulo wpf deve essere trascinato, indipendentemente da dove è stato fatto clic, il semplice aggiramento è l'utilizzo di un delegato per attivare il metodo DragMove () sull'evento onload di Windows o sull'evento di caricamento della griglia

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

A volte, non abbiamo accesso a Window, ad es. se usiamo DevExpress, tutto ciò che è disponibile è un UIElement.

Passaggio 1: aggiungi la proprietà associata

La soluzione è:

  1. Collegarsi agli eventi MouseMove;
  2. Cerca l'albero visivo finché non troviamo il primo genitore Window;
  3. Chiama .DragMove() sul nostro Window appena scoperto.

Codice:

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

Passaggio 2: aggiungi la proprietà associata a qualsiasi elemento per lasciarlo trascinare la finestra

L'utente può trascinare l'intera finestra facendo clic su un elemento specifico, se aggiungiamo questa proprietà associata:

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

Appendice A: Esempio avanzato facoltativo

In questo esempio di DevExpress , sostituiamo la barra del titolo di una finestra di ancoraggio con il nostro rettangolo grigio, quindi assicuriamo che se l'utente fa clic e trascina detto rettangolo grigio, la finestra si trascinerà normalmente:

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

Disclaimer: I am not affiliato a DevExpress . Questa tecnica funzionerà con qualsiasi elemento utente, incluso standard WPF o Telerik (un altro eccellente provider di librerie WPF).

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

In alcuni casi si genera un'eccezione (ad esempio se sulla finestra è presente anche un'immagine cliccabile che quando si fa clic apre una finestra di messaggio. Quando si esce dalla finestra del messaggio si otterrà l'errore) È più sicuro da usare

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

Quindi sei sicuro che il pulsante sinistro sia premuto in quel momento.

3
Nick

È possibile trascinare e rilasciare un modulo facendo clic in qualsiasi punto del modulo, non solo sulla barra del titolo. Questo è utile se hai una forma senza bordi.

Questo articolo su CodeProject dimostra una possibile soluzione per implementare questo:

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

Fondamentalmente viene creato un discendente del tipo di modulo in cui vengono gestiti gli eventi mouse down, up e move. 

  • Mouse down: ricorda la posizione 
  • Spostamento del mouse: memorizza nuova posizione
  • Mouse su: posiziona il modulo in una nuova posizione

Ed ecco una soluzione simile spiegata in un video tutorial:

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

Non consentirei di trascinare il modulo quando un utente fa clic su un controllo in tale forma. Gli utenti epexct risultati diversi quando fanno clic su diversi controlli. Quando il mio modulo inizia improvvisamente a muoversi perché ho cliccato su una lista, un pulsante, un'etichetta ... ecc. quello sarebbe confusionario.

2
Christophe Geers

Questo è tutto necessario! 

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();
        }
    }
1
loi.efy
<Window
...
WindowStyle="None" MouseLeftButtonDown="WindowMouseLeftButtonDown"/>
<x:Code>
    <![CDATA[            
        private void WindowMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DragMove();
        }
    ]]>
</x:Code>

fonte

0

Il metodo più utile, sia per WPF che per Windows, esempio di WPF:

    [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);
    }
0
dexiang

Come già menzionato da @ fjch1997 è conveniente implementare un comportamento. Eccola, la logica di base è la stessa di @ loi.efy's answer :

public class DragMoveBehavior : Behavior<Window>
{
    protected override void OnAttached()
    {
        AssociatedObject.MouseMove += AssociatedObject_MouseMove;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
    }

    private void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed && sender is Window window)
        {
            // In maximum window state case, window will return normal state and
            // continue moving follow cursor
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;

                // 3 or any where you want to set window location after
                // return from maximum state
                Application.Current.MainWindow.Top = 3;
            }

            window.DragMove();
        }
    }
}

Uso:

<Window ...
        xmlns:h="clr-namespace:A.Namespace.Of.DragMoveBehavior"
        xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity">
    <i:Interaction.Behaviors>
        <h:DragMoveBehavior />
    </i:Interaction.Behaviors>
    ...
</Window>
0
stop-cran