Answers:
当然,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毫秒内触发,则取消操作。
MouseLeftButtonDown
它具有直接路由策略,而MouseDown
具有冒泡路由策略。有关更多信息,以及要使用over的注意事项,请参见MSDN页面上的MouseLeftButtonDown的备注部分。MouseLeftButtonDown
MouseDown
如果wpf表单无论在何处单击都需要可拖动,则简单的解决方法是使用委托在Windows onload事件或网格加载事件上触发DragMove()方法
private void Grid_Loaded(object sender, RoutedEventArgs
{
this.MouseDown += delegate{DragMove();};
}
DragMove
只有在按下主鼠标按钮时才能调用该异常。
有时,我们无权访问Window
(例如,如果我们正在使用)DevExpress
,则所有可用的只是一个UIElement
。
解决方案是:
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);
}
}
}
如果我们添加以下附加属性,则用户可以通过单击特定元素来拖动整个窗口:
<Border local:EnableDragHelper.EnableDrag="True">
<TextBlock Text="Click me to drag this entire window"/>
</Border>
在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>
免责声明:我不隶属于DevExpress。该技术可与任何用户元素一起使用,包括标准WPF或Telerik(另一个优秀的WPF库提供程序)。
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
this.DragMove();
}
在某些情况下会引发异常(即,如果在窗口上还有一个可单击的图像,则在单击该图像时会打开一个消息框。当您从消息框退出时,您会得到错误提示),使用起来更安全
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
this.DragMove();
}
因此,您可以确定此时已按下向左按钮。
e.LeftButton
而不是Mouse.LeftButton
专门使用与事件args关联的按钮,即使它可能永远都没有关系。
可以通过单击表单上的任意位置(而不仅仅是标题栏)来拖放表单。如果您具有无边界格式,这将很方便。
本文在CodeProject上演示了实现此目的的一种可能的解决方案:
http://www.codeproject.com/KB/cs/DraggableForm.aspx
基本上,将创建Form类型的后代,在其中处理鼠标的下移,上移和移动事件。
这是一个视频教程中介绍的类似解决方案:
http://www.youtube.com/watch?v=tJlY9aX73Vs
当用户单击所说表单中的控件时,我将不允许拖动表单。用户单击不同的控件时会得到不同的结果。当我单击列表框,按钮,标签等导致表格突然开始移动时。那会令人困惑。
如@ fjch1997所述,实现行为很方便。在这里,核心逻辑与@ loi.efy的答案相同:
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();
}
}
}
用法:
<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>
这都是需要的!
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();
}
}
对于WPF和Windows窗体,最有用的方法是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);
}
<Window
...
WindowStyle="None" MouseLeftButtonDown="WindowMouseLeftButtonDown"/>
<x:Code>
<![CDATA[
private void WindowMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
]]>
</x:Code>