MSDN.WhiteKnight - Stack Overflow answers
Ответ на "Создание поведения WPF для перемещения окна без рамки"
Answer 1215664
Не очень понятно, зачем здесь Behavior, это бесполезный механизм, который тянет за собой стороннюю библиотеку, но при этом ничего особо не дает. Скорее я бы делал тут свой класс, производный от Window. Но сделать это через поведение можно как-то так:
<Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:local="clr-namespace:WpfApp1" Title="MainWindow" Height="350" Width="525" WindowStyle="SingleBorderWindow" > <i:Interaction.Behaviors> <local:MyBehavior/> </i:Interaction.Behaviors> <Grid x:Name="grid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Black"> <Button x:Name="bMin" Content="_" HorizontalAlignment="Right" Height="40" Margin="0,0,80,00" VerticalAlignment="Top" Background="LightBlue" Width="40" Click="bMin_Click" /> <Button x:Name="bMax" Content="□" HorizontalAlignment="Right" Height="40" Margin="0,0,40,00" VerticalAlignment="Top" Background="LightBlue" Width="40" Click="bMax_Click" /> <Button Content="X" HorizontalAlignment="Right" Height="40" Margin="0,0,0,0" VerticalAlignment="Top" Background="Red" Width="40" Click="ButtonClose_Click" /> <Button Content="Button" HorizontalAlignment="Left" Margin="49,45,0,0" VerticalAlignment="Top" Width="75" Background="Green" Foreground="White" Click="Button_Click" > </Button> </Grid> </Window>
using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Documents; using System.Windows.Interactivity; using System.Windows.Interop; using System.Runtime.InteropServices; namespace WpfApp1 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { } private void bMin_Click(object sender, RoutedEventArgs e) { this.WindowState = WindowState.Minimized; } private void bMax_Click(object sender, RoutedEventArgs e) { if (this.WindowState == System.Windows.WindowState.Normal) this.WindowState = System.Windows.WindowState.Maximized; else this.WindowState = System.Windows.WindowState.Normal; } private void ButtonClose_Click(object sender, RoutedEventArgs e) { this.Close(); } } public class MyBehavior : Behavior<Window> { IntPtr Handle; int yborder = 20; //высота области для перемещения bool loaded = false; [StructLayout(LayoutKind.Sequential)] public struct RECT { public int left, top, right, bottom; } [StructLayout(LayoutKind.Sequential)] struct NCCALCSIZE_PARAMS { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public RECT[] rgrc; public IntPtr lppos; } [DllImport("user32.dll", SetLastError = true)] static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect); [DllImport("user32.dll")] static extern bool AdjustWindowRectEx(ref RECT lpRect, uint dwStyle, bool bMenu, uint dwExStyle); [DllImport("dwmapi.dll")] static extern bool DwmDefWindowProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam, ref IntPtr plResult); static int GET_X_LPARAM(IntPtr lp) { short loword = (short)((ulong)lp & 0xffff); return loword; } static int GET_Y_LPARAM(IntPtr lp) { short hiword = (short)((((ulong)lp) >> 16) & 0xffff); return hiword; } const uint WM_NCCALCSIZE = 0x0083; const uint WM_NCHITTEST = 0x0084; const uint WM_ACTIVATE = 0x0006; const uint WM_NCACTIVATE = 0x0086; const uint WM_NCPAINT = 0x85; const uint WS_OVERLAPPED = 0x00000000; const uint WS_CAPTION = 0x00C00000; const uint WS_SYSMENU = 0x00080000; const uint WS_THICKFRAME = 0x00040000; const uint WS_MINIMIZEBOX = 0x00020000; const uint WS_MAXIMIZEBOX = 0x00010000; const uint WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; const uint HTTOPLEFT = 13; const uint HTTOPRIGHT = 14; const uint HTTOP = 12; const uint HTCAPTION = 2; const uint HTLEFT = 10; const uint HTNOWHERE = 0; const uint HTRIGHT = 11; const uint HTBOTTOM = 15; const uint HTBOTTOMLEFT = 16; const uint HTBOTTOMRIGHT = 17; const uint SM_CXSIZEFRAME = 32; const uint SM_CYSIZEFRAME = 33; //обработка координат мыши для неклиентской области IntPtr HitTestNCA(IntPtr hWnd, IntPtr wParam, IntPtr lParam) { // Get the point coordinates for the hit test. var ptMouse = new Point(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); // Get the window rectangle. RECT rcWindow; GetWindowRect(hWnd, out rcWindow); // Get the frame rectangle, adjusted for the style without a caption. RECT rcFrame = new RECT(); AdjustWindowRectEx(ref rcFrame, WS_OVERLAPPEDWINDOW & ~WS_CAPTION, false, 0); // Determine if the hit test is for resizing. Default middle (1,1). ushort uRow = 1; ushort uCol = 1; bool fOnResizeBorder = false; // Determine if the point is at the top or bottom of the window. if (ptMouse.Y >= rcWindow.top && ptMouse.Y < rcWindow.top + yborder) { uRow = 0; } // Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT) IntPtr[,] hitTests = new IntPtr[,] { { (IntPtr)HTTOPLEFT, fOnResizeBorder? (IntPtr)HTTOP : (IntPtr)HTCAPTION, (IntPtr)HTTOPRIGHT }, { (IntPtr)HTLEFT, (IntPtr)HTNOWHERE, (IntPtr)HTRIGHT}, { (IntPtr)HTBOTTOMLEFT, (IntPtr)HTBOTTOM, (IntPtr)HTBOTTOMRIGHT }, }; return hitTests[uRow, uCol]; } //обработчик сообщений для окна private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { bool fCallDWP = true; IntPtr lRet = IntPtr.Zero; if (msg == WM_NCCALCSIZE) { if (wParam != (IntPtr)0) { //убираем стандартную рамку lRet = IntPtr.Zero; handled = true; return lRet; } } if (msg == WM_NCACTIVATE) { lRet = (IntPtr)1; handled = true; return lRet; } fCallDWP = !DwmDefWindowProc(hwnd, msg, wParam, lParam, ref lRet); if (msg == WM_NCHITTEST && lRet == IntPtr.Zero) { //обработка нажатий мыши lRet = HitTestNCA(hwnd, wParam, lParam); if (lRet != (IntPtr)HTNOWHERE) { fCallDWP = false; } } //если сообщение не обработано, передаем базовой процедуре if (fCallDWP) handled = false; else handled = true; return lRet; } void Load(HwndSource source) { if (loaded) return; Handle = source.Handle; source.AddHook(new HwndSourceHook(WndProc));//регистрируем обработчик сообщений loaded = true; } protected override void OnAttached() { base.OnAttached(); HwndSource hwndSource = (HwndSource)HwndSource.FromVisual(AssociatedObject); if (hwndSource == null) { AssociatedObject.SourceInitialized += OnSourceInitialized; return; } Load(hwndSource); } void OnSourceInitialized(object sender, EventArgs e) { HwndSource hwndSource = (HwndSource)HwndSource.FromVisual(AssociatedObject); if (hwndSource == null) { WindowInteropHelper h = new WindowInteropHelper(AssociatedObject); hwndSource = HwndSource.FromHwnd(h.Handle); } Load(hwndSource); } } }
Здесь убирается стандартная рамка с помощью обработки WM_NCCALCSIZE и восстанавливается возможность перемещения окна перетаскиванием за область высотой в 20 пикселей в верхней части (модификация способа из https://ru.stackoverflow.com/a/1130986/240512).
Content is retrieved from StackExchange API.
Auto-generated by ruso-archive tools.