internal static void EnableBlur(Window win) { // ウィンドウに半透明のアクリル効果を適用する var state = AcrylicWindow.GetAcrylicAccentState(win); SetBlur(win, state); if (!_internalStateTable.TryGetValue(win, out var _)) { var windowHelper = new WindowInteropHelper(win); var source = HwndSource.FromHwnd(windowHelper.Handle); source.AddHook(WndProc); // タイトルバーの各種ボタンで利用するコマンドの設定 var closeBinding = new CommandBinding(SystemCommands.CloseWindowCommand, (_, __) => { SystemCommands.CloseWindow(win); }); var minimizeBinding = new CommandBinding(SystemCommands.MinimizeWindowCommand, (_, __) => { SystemCommands.MinimizeWindow(win); }); var maximizeBinding = new CommandBinding(SystemCommands.MaximizeWindowCommand, (_, __) => { SystemCommands.MaximizeWindow(win); }); var restoreBinding = new CommandBinding(SystemCommands.RestoreWindowCommand, (_, __) => { SystemCommands.RestoreWindow(win); }); win.CommandBindings.Add(closeBinding); win.CommandBindings.Add(minimizeBinding); win.CommandBindings.Add(maximizeBinding); win.CommandBindings.Add(restoreBinding); var internalState = new AcrylicWindowInternalState() { RestoringState = WindowRestoringState.Default, CloseCommand = closeBinding, MinimizeCommand = minimizeBinding, MaximizeCommand = maximizeBinding, RestoreCommand = restoreBinding, }; _internalStateTable.Add(win, internalState); // フルスクリーン状態だったら、ウィンドウサイズの訂正をする if (win.WindowState == WindowState.Maximized) { FixMaximizedWindowSize(windowHelper.Handle); } // WPFのSizeToContentのバグ対策 // (WindowChrome使用時に、SizeToContentのウィンドウサイズ計算が正しく行われない) void onContentRendered(object sender, EventArgs e) { if (win.SizeToContent != SizeToContent.Manual) { win.InvalidateMeasure(); } win.ContentRendered -= onContentRendered; InvalidateRect(windowHelper.Handle, IntPtr.Zero, true); } win.ContentRendered += onContentRendered; InvalidateRect(windowHelper.Handle, IntPtr.Zero, true); } }
private static void OnAcrylicAccentStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var win = d as Window; if (win == null) { return; } var isAcrylic = win is AcrylicWindow || AcrylicWindow.GetEnabled(win); var newValue = (AcrylicAccentState)e.NewValue; var oldValue = (AcrylicAccentState)e.OldValue; if (isAcrylic && newValue != oldValue) { AcrylicWindow.SetBlur(win, newValue); } }
protected static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == WM_ENTERSIZEMOVE) { var win = (Window)HwndSource.FromHwnd(hwnd).RootVisual; var state = AcrylicWindow.GetAcrylicAccentState(win); var value = AcrylicHelper.SelectAccentState(state); if (value == AccentState.ACCENT_ENABLE_ACRYLICBLURBEHIND) { AcrylicWindow.SetBlur(win, AcrylicAccentState.BlurBehind); InvalidateRect(hwnd, IntPtr.Zero, true); } } else if (msg == WM_EXITSIZEMOVE) { var win = (Window)HwndSource.FromHwnd(hwnd).RootVisual; var state = AcrylicWindow.GetAcrylicAccentState(win); AcrylicWindow.SetBlur(win, state); InvalidateRect(hwnd, IntPtr.Zero, true); if (win != null && _internalStateTable.TryGetValue(win, out var internalState)) { internalState.RestoringState = WindowRestoringState.Default; } } else if (msg == WM_GETMINMAXINFO) { handled = true; var hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); var monitorInfo = new MONITORINFO { cbSize = Marshal.SizeOf(typeof(MONITORINFO)) }; GetMonitorInfo(hMonitor, ref monitorInfo); var info = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); var workingRectangle = monitorInfo.rcWork; var monitorRectangle = monitorInfo.rcMonitor; var win = (Window)HwndSource.FromHwnd(hwnd).RootVisual; GetDpiForMonitor(hMonitor, MONITOR_DPI_TYPE.MDT_EFFECTIVE_DPI, out var dpiX, out var dpiY); var maxWidth = win.MaxWidth / 96.0 * dpiX; var maxHeight = win.MaxHeight / 96.0 * dpiY; var minWidth = win.MinWidth / 96.0 * dpiX; var minHeight = win.MinHeight / 96.0 * dpiY; // ウィンドウ最大化時の位置とサイズを指定 info.ptMaxPosition.x = Math.Abs(workingRectangle.left - monitorRectangle.left); info.ptMaxPosition.y = Math.Abs(workingRectangle.top - monitorRectangle.top); info.ptMaxSize.x = (int)Math.Min(Math.Abs(workingRectangle.right - monitorRectangle.left), maxWidth); info.ptMaxSize.y = (int)Math.Min(Math.Abs(workingRectangle.bottom - monitorRectangle.top), maxHeight); // ウィンドウのリサイズ可能サイズを設定 info.ptMaxTrackSize.x = (int)Math.Min(info.ptMaxTrackSize.x, maxWidth); info.ptMaxTrackSize.y = (int)Math.Min(info.ptMaxTrackSize.y, maxHeight); info.ptMinTrackSize.x = (int)Math.Max(info.ptMinTrackSize.x, minWidth); info.ptMinTrackSize.y = (int)Math.Max(info.ptMinTrackSize.y, minHeight); Marshal.StructureToPtr(info, lParam, true); return(IntPtr.Zero); } else if (msg == WM_SIZE && wParam == (IntPtr)SizeEvents.SIZE_MAXIMIZED) { FixMaximizedWindowSize(hwnd); } else if (msg == WM_SIZE && wParam == (IntPtr)SizeEvents.SIZE_RESTORED) { var win = (Window)HwndSource.FromHwnd(hwnd).RootVisual; if (win != null && _internalStateTable.TryGetValue(win, out var internalState)) { win.ClearValue(WindowStyleProperty); if (win.WindowState == WindowState.Maximized && internalState.RestoringState == WindowRestoringState.Default) { internalState.RestoringState = WindowRestoringState.RestoreMove; } if (internalState.RestoringState == WindowRestoringState.Restoring) { internalState.RestoringState = WindowRestoringState.Default; } } } else if (msg == WM_SYSCOMMAND && wParam == (IntPtr)SysCommands.SC_RESTORE) { var win = (Window)HwndSource.FromHwnd(hwnd).RootVisual; if (win != null && _internalStateTable.TryGetValue(win, out var internalState)) { internalState.RestoringState = WindowRestoringState.Restoring; } } else if (msg == WM_WINDOWPOSCHANGING) { var win = (Window)HwndSource.FromHwnd(hwnd).RootVisual; if (win != null && _internalStateTable.TryGetValue(win, out var internalState)) { var pos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS)); if (internalState.RestoringState == WindowRestoringState.RestoreMove && !(pos.x == 0 && pos.y == 0 && pos.cx == 0 && pos.cy == 0)) { GetCursorPos(out var cur); pos.y = cur.y - 8; Marshal.StructureToPtr(pos, lParam, true); } } } return(IntPtr.Zero); }