2026-09-26 12:11:20 +07:00
|
|
|
using Microsoft.UI;
|
|
|
|
|
using Microsoft.UI.Composition;
|
|
|
|
|
using Microsoft.UI.Composition.SystemBackdrops;
|
|
|
|
|
using Microsoft.UI.Windowing;
|
|
|
|
|
using Microsoft.UI.Xaml;
|
|
|
|
|
using Microsoft.UI.Xaml.Media;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using Windows.Graphics;
|
|
|
|
|
using WinRT.Interop;
|
|
|
|
|
|
|
|
|
|
namespace HearingProtector.Extensions;
|
|
|
|
|
|
|
|
|
|
#pragma warning disable SYSLIB1054
|
|
|
|
|
|
|
|
|
|
public static class MicaWindowExt
|
|
|
|
|
{
|
|
|
|
|
[DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd);
|
|
|
|
|
[DllImport("user32.dll")] private static extern bool GetCursorPos(out POINT lpPoint);
|
|
|
|
|
[StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static void SetMicaStyle(this Window window, UIElement titleBar, SizeInt32? size = null, bool canResize = true, bool canMinMax = true)
|
|
|
|
|
{
|
|
|
|
|
window.SetSystemBackdrop();
|
|
|
|
|
|
|
|
|
|
window.ExtendsContentIntoTitleBar = true;
|
|
|
|
|
window.SetTitleBar(titleBar);
|
|
|
|
|
|
|
|
|
|
// Устанавливаем место появления окна и начальный размер
|
|
|
|
|
window.CenterWindowOnCursorScreen(size, canResize, canMinMax);
|
|
|
|
|
|
|
|
|
|
// Выводим окно на передний план
|
|
|
|
|
SetForegroundWindow(WindowNative.GetWindowHandle(window));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void SetSystemBackdrop(this Window window)
|
|
|
|
|
{
|
|
|
|
|
// Проверяем версию Windows
|
|
|
|
|
if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent
|
|
|
|
|
("Windows.Foundation.UniversalApiContract", 13)) // Версия, в которой появился MicaBackdrop
|
|
|
|
|
{
|
|
|
|
|
// Используем Mica на Windows 11
|
|
|
|
|
window.SystemBackdrop = new MicaBackdrop()
|
|
|
|
|
{
|
|
|
|
|
Kind = MicaKind.Base // Или MicaKind.Alt для Mica Alt
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Используем Acrylic на Windows 10
|
|
|
|
|
//SystemBackdrop = new DesktopAcrylicBackdrop();
|
2026-09-28 08:19:48 +07:00
|
|
|
window.SystemBackdrop = new DesktopAcrylicBackdrop();
|
2026-09-26 12:11:20 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void CenterWindowOnCursorScreen(this Window window, SizeInt32? size, bool canResize = true, bool canMinMax = true)
|
|
|
|
|
{
|
|
|
|
|
// Получаем AppWindow текущего окна
|
|
|
|
|
IntPtr hWnd = WindowNative.GetWindowHandle(window);
|
2026-09-28 08:19:48 +07:00
|
|
|
Microsoft.UI.WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
|
2026-09-26 12:11:20 +07:00
|
|
|
AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
|
|
|
|
|
|
|
|
|
|
// Получаем позицию курсора
|
|
|
|
|
GetCursorPos(out POINT cursorPos);
|
|
|
|
|
|
|
|
|
|
// Находим дисплей с курсором
|
|
|
|
|
DisplayArea displayArea = DisplayArea.GetFromPoint(
|
|
|
|
|
new PointInt32(cursorPos.X, cursorPos.Y),
|
|
|
|
|
DisplayAreaFallback.Nearest);
|
|
|
|
|
|
|
|
|
|
if (!size.HasValue)
|
|
|
|
|
size = appWindow.Size;
|
|
|
|
|
|
|
|
|
|
// Центрируем окно на этом дисплее
|
|
|
|
|
appWindow.MoveAndResize(new RectInt32(
|
|
|
|
|
displayArea.WorkArea.X + (displayArea.WorkArea.Width - size.Value.Width) / 2,
|
|
|
|
|
displayArea.WorkArea.Y + (displayArea.WorkArea.Height - size.Value.Height) / 2,
|
|
|
|
|
size.Value.Width, size.Value.Height));
|
|
|
|
|
|
|
|
|
|
// Запрещаем пользовательское изменение размера
|
|
|
|
|
if (!canResize && appWindow.Presenter is OverlappedPresenter presenter)
|
|
|
|
|
{
|
|
|
|
|
presenter.IsResizable = false;
|
|
|
|
|
// При желании можно также запретить сворачивание/разворачивание:
|
|
|
|
|
if (!canMinMax)
|
|
|
|
|
{
|
|
|
|
|
presenter.IsMaximizable = false;
|
|
|
|
|
presenter.IsMinimizable = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Кастомный Backdrop для Windows 10
|
|
|
|
|
public partial class Windows10AcrylicBackdrop : SystemBackdrop
|
|
|
|
|
{
|
|
|
|
|
DesktopAcrylicController? controller;
|
|
|
|
|
|
|
|
|
|
protected override void OnTargetConnected(ICompositionSupportsSystemBackdrop connectedTarget, XamlRoot xamlRoot)
|
|
|
|
|
{
|
|
|
|
|
// Call the base method to initialize the default configuration object.
|
|
|
|
|
base.OnTargetConnected(connectedTarget, xamlRoot);
|
|
|
|
|
|
|
|
|
|
// This example does not support sharing MicaSystemBackdrop instances.
|
|
|
|
|
if (controller is not null)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception("This controller cannot be shared");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
controller = new DesktopAcrylicController();
|
|
|
|
|
// Set configuration.
|
|
|
|
|
SystemBackdropConfiguration defaultConfig = GetDefaultSystemBackdropConfiguration(connectedTarget, xamlRoot);
|
|
|
|
|
controller.SetSystemBackdropConfiguration(defaultConfig);
|
|
|
|
|
// Add target.
|
|
|
|
|
controller.AddSystemBackdropTarget(connectedTarget);
|
|
|
|
|
|
|
|
|
|
controller.TintOpacity = 0.8f;
|
|
|
|
|
controller.LuminosityOpacity = 0.9f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void OnTargetDisconnected(ICompositionSupportsSystemBackdrop disconnectedTarget)
|
|
|
|
|
{
|
|
|
|
|
base.OnTargetDisconnected(disconnectedTarget);
|
|
|
|
|
|
|
|
|
|
controller?.RemoveSystemBackdropTarget(disconnectedTarget);
|
|
|
|
|
controller = default;
|
|
|
|
|
}
|
|
|
|
|
}
|