어떤 요소를 클릭하든 WPF 창을 드래그 가능하게 만듭니다.
내 질문은 두 배이며 WinForms의 표준 솔루션 (이 설명을하기 전에 Christophe Geers가 제공 한)보다 WPF에서 제공하는 두 가지 모두에 대한 더 쉬운 솔루션이 있기를 바랍니다 .
첫째, 마우스 클릭 + 드래그 이벤트를 캡처 및 처리하지 않고 창을 드래그 할 수있는 방법이 있습니까? 내 말은 창을 제목 표시 줄로 드래그 할 수 있음을 의미하지만 창을 갖지 않도록 설정하고 여전히 드래그 할 수 있도록하려면 제목 표시 줄 드래그를 처리하는 모든 이벤트를 어떻게 든 리디렉션 할 수있는 방법이 있습니까? ?
둘째, 윈도우의 모든 요소에 이벤트 핸들러를 적용하는 방법이 있습니까? 에서와 같이 사용자가 클릭 + 드래그하는 요소에 관계없이 창을 드래그 할 수 있도록합니다. 모든 단일 요소에 핸들러를 수동으로 추가하지 않아도됩니다. 어딘가에서 한 번만?
물론입니다. 다음 MouseDown
이벤트를 적용 하세요.Window
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
this.DragMove();
}
이렇게하면 사용자가 MouseDown 이벤트 ( e.Handled = true
) 를 먹는 컨트롤을 제외하고 모든 컨트롤을 클릭 / 드래그 할 때 창을 드래그 할 수 있습니다.
PreviewMouseDown
대신을 사용할 수 MouseDown
있지만 드래그 이벤트가 이벤트를 잡아서 Click
창이 왼쪽 마우스 클릭 이벤트에 응답하지 않습니다. 컨트롤에서 폼을 클릭하고 드래그 할 수 있도록하려면을 사용하고 PreviewMouseDown
, 타이머를 시작하여 드래그 작업을 시작하고, MouseUp
이벤트가 X 밀리 초 이내에 발생 하면 작업을 취소 할 수 있습니다 .
wpf 양식을 클릭 한 위치에 관계없이 드래그 할 수 있어야하는 경우 쉬운 해결 방법은 대리자를 사용하여 windows onload 이벤트 또는 그리드로드 이벤트에서 DragMove () 메서드를 트리거하는 것입니다.
private void Grid_Loaded(object sender, RoutedEventArgs
{
this.MouseDown += delegate{DragMove();};
}
경우에 따라에 대한 액세스 권한이 없습니다 Window
. 예를 들어를 사용 DevExpress
하는 경우 사용할 수있는 모든 것은 UIElement
.
1 단계 : 연결된 속성 추가
해결책은 다음과 같습니다.
- 에 후크
MouseMove
이벤트; - 첫 번째 부모를 찾을 때까지 시각적 트리를 검색합니다
Window
. - 전화
.DragMove()
새로 발견 된 우리에Window
.
암호:
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);
}
}
}
2 단계 : 창을 끌 수 있도록 요소에 연결된 속성 추가
이 연결된 속성을 추가하면 사용자는 특정 요소를 클릭하여 전체 창을 끌 수 있습니다.
<Border local:EnableDragHelper.EnableDrag="True">
<TextBlock Text="Click me to drag this entire window"/>
</Border>
부록 A : 선택적 고급 예
DevExpress 의이 예에서는 도킹 창의 제목 표시 줄을 자체 회색 직사각형으로 바꾼 다음 사용자가 회색 직사각형을 클릭하고 드래그하면 창이 정상적으로 드래그되는지 확인합니다.
<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 affiliated with DevExpress. This technique will work with any user element, including standard WPF or Telerik (another fine WPF library provider).
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
this.DragMove();
}
Is throwing an exception in some cases (i.e. if on the window you also have a clickable image that when clicked opens a message box. When you exit from message box you will get error) It is safer to use
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
this.DragMove();
}
So you are sure that left button is pressed at that moment.
It is possible to drag & drop a form by clicking anywhere on the form, not just the title bar. This is handy if you have a borderless form.
This article on CodeProject demonstrates one possible solution to implement this:
http://www.codeproject.com/KB/cs/DraggableForm.aspx
Basically a descendant of the Form type is created in which the mouse down, up and move events are handled.
- Mouse down: remember position
- Mouse move: store new location
- Mouse up: position form to new location
And here's a similar solution explained in a video tutorial:
http://www.youtube.com/watch?v=tJlY9aX73Vs
I would not allow dragging the form when a user clicks upon a control in said form. Users epexct different results when they click on different controls. When my form suddenly starts moving because I clicked a listbox, button, label...etc. that would be confusing.
This is all needed!
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();
}
}
As already mentioned by @fjch1997 it's convenient to implement a behavior. Here it is, the core logic is the same as in the @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();
}
}
}
Usage:
<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>
The most usefull method, both for WPF and windows form, WPF example:
[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);
}
<Window
...
WindowStyle="None" MouseLeftButtonDown="WindowMouseLeftButtonDown"/>
<x:Code>
<![CDATA[
private void WindowMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
]]>
</x:Code>
'development' 카테고리의 다른 글
ExpandableListView-자식이없는 그룹에 대한 표시기 숨기기 (0) | 2020.08.15 |
---|---|
C 빅 엔디안 또는 리틀 엔디안 머신을 결정하는 매크로 정의? (0) | 2020.08.15 |
node.js를 사용하여 mySQL에서 대량 삽입을 수행하는 방법 (0) | 2020.08.15 |
C ++, 'if'표현식의 변수 선언 (0) | 2020.08.15 |
어셈블리 오류에서 유형을로드 할 수 없습니다. (0) | 2020.08.15 |