【问题标题】:How do you disable Aero Snap in an application?如何在应用程序中禁用 Aero Snap?
【发布时间】:2010-03-18 14:45:56
【问题描述】:

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

【问题讨论】:

  • 您是否希望以编程方式为整个系统关闭此功能?还是只针对一个窗口?
  • 我只想为我的应用程序的窗口关闭它。不适用于整个系统。
  • 不可能。这是一个全有或全无的提议。我会尝试修改我的表单以防止调整大小。 (我这里没有Win7系统,所以无法测试)
  • 但是例如windows7的notesoftware的windows,不停靠,但是可以调整大小。
  • 我建议不要尝试这个。我使用的另一个程序是航空证明(我不认为它是 .NET),它真的很烦人。

标签: c# wpf aero


【解决方案1】:

我最近需要对没有窗口装饰(没有标题栏和按钮)的自定义、可调整大小的ResizeMode = CanResizeWithGrip WPF 窗口执行此操作。我使用DragMove()移动窗口,当它被AeroSnap最大化时,窗口变得不可移动并因此锁定到位。

我尝试了Barn Monkey's solution,它部分工作,但它仍会显示 AeroSnap 图形并将应用程序大小调整为全屏大小。我在下面对其进行了修改,现在它按预期工作:仍然可以调整大小,但根本没有 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>

而且它确实有效!

【讨论】:

  • 优秀的解决方案!只是我的问题,这个解决方案在复制过去后立即起作用;D
  • 修改此代码对我来说效果很好,但我花了一段时间......在我的第一次尝试中,MouseUp 从未被解雇。这是因为我在 Window 上使用了 ControlTemplate,而该模板的主要成员是一个简单的 。首先,在我将其修改为 之后,所有内容都被四舍五入了。
  • @JanZeman,是的,事件处理程序位于根窗口上,因此如果有任何子控件拦截用户输入,事件将不会到达窗口。此外,如果控件/窗口设置为透明,则鼠标事件会通过它(不会触发任何事件)。
  • @bj0 请修正xmlns 声明中&lt;UserControl ... 下方的错字utli
【解决方案2】:

如果您以 Win7 的“便签”为例,您可能已经注意到它没有标准的窗口边框。在此基础上,我只能告诉您,没有直接的方法可以做到这一点,除非您设置 ResizeMode="NoResize" 并手动处理调整大小行为。以下是我快速创建的一个非常基本的非专业解决方案以帮助您入门,但如果您愿意,您可以附加更多功能:)

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

您甚至可以制作一个可以在其父画布中调整大小和移动的控件(基本上是一个面板)。现在这个控件可以填充到一个透明的最大化窗口中。这会让您错觉您的控件是一个不响应“窗口捕捉”并且不会停靠的窗口!

希望这会有所帮助。
问候,
米希尔·戈卡尼

【讨论】:

    【解决方案3】:

    我使用 anthony 的解决方案有一段时间了,但是如果您切换 ResizeMode,窗口会暂时移除尺寸边框,这有点令人讨厌。这是另一个解决方案。通过设置 WS_OVERLAPPEDWINDOW 标志并删除 WS_THICKFRAME 标志将禁用窗口的 Aero Snap 功能,而不会临时删除尺寸边框。您可以使用样式来获得您需要的确切样式,但关键是删除 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);
    

    【讨论】:

      【解决方案4】:

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

      编辑: alexandrud 正确地指出,这仅适用于“无边界”窗口(在 WPF 术语中,WindowStyle = None)。

      许多博萨人为了给我们带来这些信息而死。

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

      【讨论】:

      • 这不起作用。当您拖动窗口时,窗口的边框会消失,并且不会再出现。
      • 啊,感谢您指出这一点。我在无边框窗口中使用此代码,所以我从未注意到这个问题。
      【解决方案5】:

      我需要检测 Windows 7 Aero snaps/docks 以防止 WPF 应用程序上的窗口大小发生变化。在搜索过程中,我偶然发现了这篇文章,发现anthony 给出的答案非常有帮助。

      以下对我有用。

      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's response优雅地为我解决了问题。

      【讨论】:

        【解决方案6】:

        这对你来说可能不是完美的解决方案,但对我来说,将表单设置为不可调整大小就可以了。

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

            我这里没有 Windows 7 盒子,所以我无法对此进行测试,但我会尝试以下方法:

            1- 创建一个测试表单并覆盖 WndProc
            2- 测试并记录与大小、位置和 WindowState 变化有关的特定消息。
            3-确定如果停靠时发送到窗口的消息是 Size/Position/WindowState 的组合,或者是否有另一个新的 Windows 7 消息(5 分钟的搜索没有向我透露任何信息.)
            4- 收到消息后,检查是否存在“独特”情况。
            5- 修改您的代码以适应这种独特的情况。

            如果没有其他人提出任何建议,我可能会在这个周末在家试一试。

            【讨论】:

              【解决方案9】:

              我发现一个相当简单的解决方案也适用于无边框窗口:只需隐藏最大化按钮(如果由于缺少标题栏而尚未显示的事件):

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

              【讨论】:

                【解决方案10】:

                在 Windows 10 上设置“this.MaximizeBox = false”实际上会为我破坏 Snap。 也许这对你有用?

                【讨论】:

                  【解决方案11】:

                  我们开始...

                  我终于找到了真正的解决方案。

                  我正在为我的应用程序寻找真正的解决方案。 我为此浪费了一整天的时间。 有很多技巧,但是使用reg我们需要重新启动计算机。

                  您可以从 powershell 禁用它。您需要从您的代码中调用此文件。

                  这是链接。

                  检查底部名为“DisableAeroSnap.ps1”的下载文件

                  https://michlstechblog.info/blog/windows-disable-aerosnap-automatically-window-arranging-and-resizing-while-dragging/#more-951

                  干杯!!!

                  【讨论】:

                    【解决方案12】:

                    在控制面板的“轻松访问”中,选择

                    更容易专注于任务

                    打勾

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

                    【讨论】:

                    • 这没有回答问题。
                    • 它回答了所问的问题,如果您觉得它不请更具体。 “这不能回答问题”与巧克力茶壶一样有用。
                    • 巧克力茶壶很好用,可以吃:)
                    猜你喜欢
                    • 2011-02-24
                    • 2014-11-08
                    • 1970-01-01
                    • 2012-06-17
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2020-10-10
                    相关资源
                    最近更新 更多