Эта проблема, по-видимому, известна внутри корпорации Майкрософт, когда " Сенсорная система WPF не всегда правильно определяет изменения разрешения. "
Перефразируя комментарии, обходной путь заключается в том, чтобы подписаться на SystemEvents.DisplaySettingsChanged
, а после небольшой задержки репостить WM_DISPLAYCHANGE
в окне с заголовком «SystemResourceNotifyWindow» в текущем потоке.
Однако фактический код, размещенный там, не подходит ни для кого, кроме Microsoft. Код ниже будет работать для всех нас. Я разместил пример решения здесь, на GitHub .
class NativeRotationFix
{
private readonly Window window;
private const string MessageWindowTitle = "SystemResourceNotifyWindow";
private const uint WM_DISPLAYCHANGE = 0x007E;
private const int Delay = 500;
private int width;
private int height;
private int depth;
public delegate bool WNDENUMPROC(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool EnumThreadWindows(uint dwThreadId, WNDENUMPROC lpfn, IntPtr lParam);
[DllImport("user32.dll")]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
public NativeRotationFix(Window window)
{
this.window = window;
SystemEvents.DisplaySettingsChanged += OnDisplaySettingsChanged;
}
~NativeRotationFix()
{
SystemEvents.DisplaySettingsChanged -= OnDisplaySettingsChanged;
}
private void OnDisplaySettingsChanged(object sender, EventArgs e)
{
new DispatcherTimer(TimeSpan.FromMilliseconds(Delay), DispatcherPriority.Normal, (s, a) =>
{
WindowInteropHelper interopHelper = new WindowInteropHelper(window);
Screen screen = Screen.FromHandle(interopHelper.Handle);
width = screen.Bounds.Width;
height = screen.Bounds.Height;
depth = screen.BitsPerPixel;
uint threadId = GetCurrentThreadId();
EnumThreadWindows(threadId, PostToNotifyWindow, IntPtr.Zero);
(s as DispatcherTimer).Stop();
}, Dispatcher.CurrentDispatcher);
}
private bool PostToNotifyWindow(IntPtr hwnd, IntPtr lparam)
{
StringBuilder buffer = new StringBuilder(MessageWindowTitle.Length + 1);
if (GetWindowText(hwnd, buffer, buffer.Capacity) <= 0) return true;
if (buffer.ToString() != MessageWindowTitle) return true;
PostMessage(hwnd, WM_DISPLAYCHANGE, new IntPtr(depth), new IntPtr(MakeLong(width, height)));
return false;
}
private static int MakeLong(int low, int high)
{
return (int)((ushort)low | (uint)high << 16);
}
}