如何在应用程序中禁用Aero Snap?

是否有可能在WPF应用程序中禁用Windows 7的自动窗口停靠function?

我最近需要这样做到一个自定义的,可resizeResizeMode = CanResizeWithGrip WPF窗口没有窗口装饰(没有标题栏和button)。 我使用DragMove()来移动窗口,当它被AeroSnap最大化时,窗口变得不可移动,因此locking到位。

我试过谷仓猴的解决scheme ,这部分工作,但它仍然会显示AeroSnapgraphics和调整应用程序的全屏尺寸。 我修改下面,现在它的工作原理:仍然可以resize,但没有AeroSnap。

 void Window1_MouseDown(object sender, MouseButtonEventArgs e) { if( e.LeftButton == MouseButtonState.Pressed ) { // this prevents win7 aerosnap if( this.ResizeMode != System.Windows.ResizeMode.NoResize ) { this.ResizeMode = System.Windows.ResizeMode.NoResize; this.UpdateLayout(); } DragMove(); } } void Window1_MouseUp( object sender, MouseButtonEventArgs e ) { if( this.ResizeMode == System.Windows.ResizeMode.NoResize ) { // restore resize grips this.ResizeMode = System.Windows.ResizeMode.CanResizeWithGrip; this.UpdateLayout(); } } 

编辑:

我写这篇文章已经有一段时间了,但是由于人们仍然在看这个,所以我会用我现在使用的东西来更新它。 我仍然使用基本上相同的方法来防止边缘捕捉和移动我的窗口,但我现在已经把它们打包到自定义的Behavior<>类我可以附加到WindowUserControl 。 这使得它们非常容易与MVVM(我使用Caliburn Micro)一起使用。

行为类是:

 /// <summary> /// behavior that makes a window/dialog draggable by clicking anywhere /// on it that is not a control (ie, button) /// </summary> public class DragMoveBehavior<T> : Behavior<T> where T : FrameworkElement { protected override void OnAttached() { AssociatedObject.MouseLeftButtonDown += MouseDown; base.OnAttached(); } protected override void OnDetaching() { AssociatedObject.MouseLeftButtonDown -= MouseDown; base.OnDetaching(); } void MouseDown( object sender, EventArgs ea ) => Window.GetWindow( sender as T )?.DragMove(); } public class WinDragMoveBehavior : DragMoveBehavior<Window> { } public class UCDragMoveBehavior : DragMoveBehavior<UserControl> { } /// <summary> /// behavior that makes a window/dialog not resizable while clicked. this prevents /// the window from being snapped to the edge of the screen (AeroSnap). if DragMoveBehavior /// is also used, this must be attached first. /// </summary> /// <typeparam name="T"></typeparam> public class NoSnapBehavior<T> : Behavior<T> where T : FrameworkElement { ResizeMode lastMode = ResizeMode.NoResize; protected override void OnAttached() { AssociatedObject.MouseLeftButtonDown += MouseDown; AssociatedObject.MouseLeftButtonUp += MouseUp; base.OnAttached(); } protected override void OnDetaching() { AssociatedObject.MouseLeftButtonDown -= MouseDown; AssociatedObject.MouseLeftButtonUp -= MouseUp; base.OnDetaching(); } /// <summary> /// make it so the window can be moved by dragging /// </summary> void MouseDown( object sender, EventArgs ea ) { var win = Window.GetWindow( sender as T ); if( win != null && win.ResizeMode != ResizeMode.NoResize ) { lastMode = win.ResizeMode; win.ResizeMode = ResizeMode.NoResize; win.UpdateLayout(); } } void MouseUp( object sender, EventArgs ea ) { var win = Window.GetWindow( sender as T ); if( win != null && win.ResizeMode != lastMode ) { win.ResizeMode = lastMode; win.UpdateLayout(); } } } public class WinNoSnapBehavior : NoSnapBehavior<Window> { } public class UCNoSnapBehavior : NoSnapBehavior<UserControl> { } 

然后我将它们附加到我的对话框视图:

 <UserControl ... xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:util:="..."> <i:Interaction.Behaviors> <util:UCNoSnapBehavior/> <util:UCDragMoveBehavior/> </i:Interaction.Behaviors> ... </UserControl> 

它只是工作!

如果你正在给Win7的“粘滞便笺”的例子,你可能已经注意到它没有标准的窗口边界。 作为一个基础,我只能告诉你,除了设置ResizeMode="NoResize"和手动处理resize行为,没有直接的方法。 以下是一个非常基本的,非专业的解决scheme,我已经很快创build,以便您开始,但是如果您喜欢,您可以添加更多function:)

 <Window x:Class="WpfApplication1.Window1" x:Name="window" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Width="300" Height="300" ResizeMode="NoResize" WindowStyle="None" AllowsTransparency="True" Background="Transparent" WindowState="Maximized"> <Window.Resources> <x:Array x:Key="TextBlockList" Type="{x:Type TextBlock}"> <TextBlock Text="○ Resize Horizontally by dragging right grip" /> <TextBlock Text="○ Resize Vertically by dragging bottom grip" /> <TextBlock Text="○ Move Horizontally by dragging left grip" /> <TextBlock Text="○ Move Verticallyby dragging top grip" /> </x:Array> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="{Binding Height, Mode=OneWay, ElementName=window}" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="{Binding Width, Mode=OneWay, ElementName=window}" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <GridSplitter Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" MinWidth="5" /> <GridSplitter Grid.Column="1" Grid.Row="1" HorizontalAlignment="Right" MinWidth="5" /> <GridSplitter Grid.Column="1" Grid.Row="1" VerticalAlignment="Top" MinHeight="5" ResizeDirection="Rows" HorizontalAlignment="Stretch" /> <GridSplitter Grid.Column="1" Grid.Row="1" VerticalAlignment="Bottom" MinHeight="5" ResizeDirection="Rows" HorizontalAlignment="Stretch" /> <Border Grid.Column="1" Grid.Row="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" Margin="5"> <Grid x:Name="root"> <ItemsControl ItemsSource="{StaticResource TextBlockList}" /> </Grid> </Border> </Grid> </Window> 

你甚至可以做一个控件(基本上是一个面板),可以resize,并在其父canvas中移动。 现在这个控件可以填充到一个透明的最大化窗口中。 这将给你一个错觉,你的控制是一个窗口,不响应“窗口捕捉”,不会停靠!

希望这可以帮助。
问候,
Mihir Gokani

我在一段时间里使用了anthony的解决scheme,但是如果切换ResizeMode,窗口会暂时移除大小的边框,这有点烦人。 这是另一个解决scheme。 通过设置WS_OVERLAPPEDWINDOW标志并删除WS_THICKFRAME标志将禁用窗口的Aero Snapfunction,同时不临时删除调整边框。 您可以使用样式来获得所需的确切样式,但关键是删除WS_THICKFRAME标志。

  public enum WindowStyles: int { WS_BORDER = 0x00800000, WS_CAPTION = 0x00C00000, WS_CHILD = 0x40000000, WS_CHILDWINDOW = 0x40000000, WS_CLIPCHILDREN = 0x02000000, WS_CLIPSIBLINGS = 0x04000000, WS_DISABLED = 0x08000000, WS_DLGFRAME = 0x00400000, WS_GROUP = 0x00020000, WS_HSCROLL = 0x00100000, WS_ICONIC = 0x20000000, WS_MAXIMIZE = 0x01000000, WS_MAXIMIZEBOX = 0x00010000, WS_MINIMIZE = 0x20000000, WS_MINIMIZEBOX = 0x00020000, WS_OVERLAPPED = 0x00000000, WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, WS_POPUP = unchecked((int)0x80000000), WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU, WS_SIZEBOX = 0x00040000, WS_SYSMENU = 0x00080000, WS_TABSTOP = 0x00010000, WS_THICKFRAME = 0x00040000, WS_TILED = 0x00000000, WS_TILEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, WS_VISIBLE = 0x10000000, WS_VSCROLL = 0x00200000, } int newWinLongStyle = 0; newWinLongStyle |= (int)WindowStyles.WS_OVERLAPPEDWINDOW; newWinLongStyle ^= (int)WindowStyles.WS_THICKFRAME; WindowInteropHelper helper = new WindowInteropHelper(this); NativeMethods.SetWindowLong(helper.Handle, (int)WindowStyles.GWL_STYLE, newWinLongStyle); 

我需要检测Windows 7 Aero捕捉/停靠,以防止WPF应用程序的窗口大小更改。 在我的search过程中,我偶然发现了这个post,发现了安东尼给出的答案非常有帮助。

以下是为我工作。

 private void DisplayWindow_MouseMove(object sender, MouseEventArgs e) { if (e.LeftButton == MouseButtonState.Released) { this.ResizeMode = System.Windows.ResizeMode.CanResizeWithGrip; } } private void DisplayWindow_LocationChanged(object sender, EventArgs e) { this.ResizeMode = System.Windows.ResizeMode.NoResize; } 

该窗口的XAML具有ResizeMode="CanResizeWithGrip"设置。

编辑
我的回应是不适当地处理Windows 7 Aero快照。 bjo的回应优雅地解决了我的问题。

这是我的解决scheme。 如果将其ResizeMode设置为ResizeMode.NoResize,则Windows将不会捕捉,因此,诀窍在于可靠地确定拖动/移动何时开始和结束。

编辑: alexandrud正确指出,这将只适用于“无边界”的窗口(WindowStyle =无WPF术语)。

许多Bothans死亡给我们带来这个信息。

 class NoSnapWindow : System.Windows.Window { public NoSnapWindow() { SourceInitialized += delegate { var source = HwndSource.FromVisual(this) as HwndSource; source.AddHook(SourceHook); }; } private IntPtr SourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case 0x112: // WM_SYSCOMMAND switch (wParam.ToIn32() & ~0x0F) { case 0xF010: // SC_MOVE ResizeMode = ResizeMode.NoResize; break; } break; case 0x2A2: // WM_MOUSELEAVE ResizeMode = ResizeMode.CanResize; break; } return IntPtr.Zero; } } 

这可能不是完美的解决scheme,但对于我来说,设置不可resize的forms是一个窍门。

DragMove挂起UI线程。 该代码也适用。

 void Window1_MouseDown(object sender, MouseButtonEventArgs e) { if( e.LeftButton == MouseButtonState.Pressed ) { // this prevents win7 aerosnap this.ResizeMode = System.Windows.ResizeMode.NoResize; this.UpdateLayout(); DragMove(); // restore resize grips this.ResizeMode = System.Windows.ResizeMode.CanResizeWithGrip; this.UpdateLayout(); } } 

我没有在这里的Windows 7框,所以我不能testing这个,但这是我会尝试:

1-创build一个testing表单并覆盖WndProc
2-testing并logging有关Size,Position和WindowState更改的特定消息。
3-确定停靠时发送到窗口的消息是Size / Position / WindowState的组合还是另一个新的Windows 7消息(5分钟的search没有透露任何东西给我)。
4-一旦你有消息,检查是否有一个“独特的”正在发生的情况。
5-修改您的代码以适应这种独特的情况。

如果没有其他人提出任何事情,我可能会在这个周末在家里的旋转。

我发现一个相当简单的解决scheme,使用无边框窗口:只需隐藏最大化button(如果由于缺less标题栏已经不显示,则为事件):

  [DllImport("user32.dll")] private static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); private const int GWL_STYLE = -16; private const int WS_MAXIMIZEBOX = 0x10000; private void Window_OnSourceInitialized(object sender, EventArgs e) { var hwnd = new WindowInteropHelper((Window)sender).Handle; var value = GetWindowLong(hwnd, GWL_STYLE); SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MAXIMIZEBOX)); } 

在控制面板中轻松访问,select

更容易专注于任务

并打勾

移动到屏幕边缘时防止窗口自动排列