Как отключить 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».
Ваше здоровье !!!
У меня нет коробки с Windows 7, поэтому я не могу проверить это, но вот что я попробую:
1. Создайте тестовую форму и переопределите WndProc.
2- Протестируйте и запишите конкретные сообщения, касающиеся изменения размера, положения и состояния окна.
3. Определите, являются ли сообщения, отправляемые окну, когда они закреплены, комбинацией Size/Position/WindowState или есть другое, новое сообщение Windows 7 (5 минут поиска ничего мне не показали).
4- Получив сообщения, проверьте, не происходит ли "уникальный" случай.
5- Измените свой код, чтобы приспособиться к этому уникальному случаю.
Если никто больше не придумает ничего, я мог бы поднять это дома в эти выходные.
Установка "this.MaximizeBox = false" на самом деле нарушает Snap для меня в Windows 10. Может быть, это будет работать для вас?
В Ease of Access на панели управления выберите
Облегчить сосредоточение на задачах
и отметьте
Запретить автоматическое расположение окон при перемещении к краю экрана