Как отключить Aero Snap в приложении?

Можно ли отключить функцию автоматической стыковки окон в Windows 7 в приложении WPF?

12 ответов

Мне недавно нужно было сделать это на заказ, изменяемый размер ResizeMode = CanResizeWithGrip Окно WPF без оконных украшений (без заголовка и кнопок). я использовал DragMove() переместить окно, и когда оно развернуто AeroSnap, окно становится неподвижным и, следовательно, фиксируется на месте.

Я попробовал решение Barn Monkey, которое частично работало, но оно все равно показывало бы изображение 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<> классы, которые я могу прикрепить к Window или же UserControl, Это делает их очень простыми в использовании с 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> { }

Затем я присоединяю их к своему диалоговому окну Views:

<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" и обработка поведения изменения размера вручную. Ниже приведено очень простое, непрофессиональное решение, которое я быстро создал, чтобы вы начали, но вы можете добавить больше функций, если хотите:)

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

Вы даже можете создать элемент управления (в основном панель), размер которого можно изменить и переместить в его родительский холст. Теперь этот элемент управления можно заполнить в прозрачное развернутое окно. Это создаст у вас иллюзию того, что вы управляете окном, которое не реагирует на "привязку окна" и не стыкуется!

Надеюсь это поможет.
С Уважением,
Михир Гокани

Некоторое время я использовал решение Энтони, но если вы переключите 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);

Мне нужно было обнаруживать привязки / доки Windows 7 Aero, чтобы предотвратить изменение размера окна в приложении WPF. Во время поиска я наткнулся на этот пост и нашел ответ Энтони очень полезным.

Вот что сработало для меня.

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 элегантно решил проблему для меня.

Вот мое решение. Windows не будет привязываться, если их ResizeMode установлен в ResizeMode.NoResize, поэтому хитрость заключается в том, чтобы надежно определить, когда перетаскивание начинается или заканчивается.

РЕДАКТИРОВАТЬ: alexandrud правильно указал, что это будет работать только для окон без полей (WindowStyle = None в терминах WPF).

Многие ботаны умерли, чтобы принести нам эту информацию.

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

Возможно, это не идеальное решение для вас, но для меня установка формы с неизменяемым размером сделала свое дело.

Я нашел довольно простое решение, которое работает и с окнами без полей: просто скройте кнопку максимизации (событие, если оно уже не отображается из-за отсутствия панели заголовка):

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

DragMove приостанавливает поток пользовательского интерфейса. Этот код также работает.

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

Вот так ...

Наконец я нашел реальное решение для этого.

Я искал реальное решение для своего приложения. Я потратил на это весь день. Есть много хитростей, но с помощью reg нам нужно перезагрузить компьютер.

Вы можете отключить его из powershell. Вам нужно вызвать этот файл из вашего кода.

Вот ссылка.

Проверьте файл загрузки внизу под названием «DisableAeroSnap.ps1».

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

Ваше здоровье !!!

У меня нет коробки с Windows 7, поэтому я не могу проверить это, но вот что я попробую:

1. Создайте тестовую форму и переопределите WndProc.
2- Протестируйте и запишите конкретные сообщения, касающиеся изменения размера, положения и состояния окна.
3. Определите, являются ли сообщения, отправляемые окну, когда они закреплены, комбинацией Size/Position/WindowState или есть другое, новое сообщение Windows 7 (5 минут поиска ничего мне не показали).
4- Получив сообщения, проверьте, не происходит ли "уникальный" случай.
5- Измените свой код, чтобы приспособиться к этому уникальному случаю.

Если никто больше не придумает ничего, я мог бы поднять это дома в эти выходные.

Установка "this.MaximizeBox = false" на самом деле нарушает Snap для меня в Windows 10. Может быть, это будет работать для вас?

В Ease of Access на панели управления выберите

Облегчить сосредоточение на задачах

и отметьте

Запретить автоматическое расположение окон при перемещении к краю экрана

Другие вопросы по тегам