Как исправить изменение размера формы WPF - отстающие элементы управления и черный фон?

У меня очень простое окно WPF - единственное, что в нем - кнопка, выровненная по правому краю. Когда я изменяю размер окна, перетаскивая левую границу, кнопка перепрыгивает - много. Попробуйте сами, перетащите левую границу назад и вперед.

Кроме того, черный фон временно экспонируется во время изменения размера.

В этом вопросе я задал похожий вопрос о Windows Forms. Единственный ответ, который я получил, заключается в том, что это исправлено в WPF, однако, как ни удивительно, оно не только не исправлено, но и в WPF добавлена ​​вторая визуальная ошибка - временный черный фон.

Вот как выглядит задержка управления; это происходит, когда я изменяю размер окна по его верхней границе (записано камерой, потому что экранная крышка делала его менее заметным, делая все медленным):

Пример черной рамки: это было захвачено при изменении размера окна; это только так на долю секунды, но это очень заметно:

Я делаю что-то неправильно? Как сделать так, чтобы мои элементы управления визуально находились в одном месте при изменении размеров? Как я могу избежать черной границы?

Примечание: кнопка в конечном итоге оказывается в правильном месте - она ​​только ненадолго прыгает во время изменения размера.

5 ответов

Решение

Это полный рабочий код, основанный на втором решении Wieser Software Ltd.

public partial class MainView : Window
{
    public MainView()
    {
        InitializeComponent();

        //ensure win32 handle is created
        var handle = new WindowInteropHelper(this).EnsureHandle();

        //set window background
        var result = SetClassLong(handle, GCL_HBRBACKGROUND, GetSysColorBrush(COLOR_WINDOW));
    }

    public static IntPtr SetClassLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
    {
        //check for x64
        if (IntPtr.Size > 4)
            return SetClassLongPtr64(hWnd, nIndex, dwNewLong);
        else
            return new IntPtr(SetClassLongPtr32(hWnd, nIndex, unchecked((uint)dwNewLong.ToInt32())));
    }

    private const int GCL_HBRBACKGROUND = -10;
    private const int COLOR_WINDOW = 5;

    [DllImport("user32.dll", EntryPoint = "SetClassLong")]
    public static extern uint SetClassLongPtr32(IntPtr hWnd, int nIndex, uint dwNewLong);

    [DllImport("user32.dll", EntryPoint = "SetClassLongPtr")]
    public static extern IntPtr SetClassLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

    [DllImport("user32.dll")]
    static extern IntPtr GetSysColorBrush(int nIndex);
}

Это не представляется возможным в текущих версиях WPF.

Есть два решения, описанные здесь: http://wieser-software.blogspot.co.uk/2012/06/wpf-window-rendering-woes.html

  1. Подключите WndProc, обработайте WM_ERASEBKGND и нарисуйте систему WINDOW_COLOR на фоне или в другом цвете в соответствии с темой вашего приложения.
  2. Вызовите SetClassLong, чтобы установить фоновую кисть класса окна

    SetClassLong(Handle, GCL_HBRBACKGROUND, GetSysColorBrush(COLOR_WINDOW));

Я считаю, что временный черный фон - это проблема WPF, связанная с тем фактом, что WPF использует DirectX в качестве механизма рендеринга, и при изменении размеров окон он должен синхронизировать рисование с системой управления окнами. Это также может объяснить, почему кнопка перемещается по отношению к окну при перетаскивании границы окна. Рисование не-клиентской области окна происходит намного медленнее, чем рисование того, что находится внутри окна, и если вы быстро перемещаете мышь на медленном компьютере, расхождения между границей и внутренними границами окна, вероятно, будут более заметными.

Предположительно, это происходит только в Vista с включенным Aero, и это должно быть исправлено в Vista SP1. Тем не менее, я только что проверил на SP2, и я все еще видел немного черного фона, но только когда Aero был включен. Моя видеокарта довольно быстрая, поэтому это было едва заметно.

Если мой анализ верен, единственный способ решить эту проблему - получить более быструю графическую карту или отключить Aero.

В других ответах рассказывалось, как залить другой цвет фона, чтобы попытаться смягчить эффект медленного рисования WPF.

Я не могу предложить никакой магии, чтобы ускорить WPF, но я могу дать некоторое представление о том, откуда берутся черные.

Визуальная ошибка на вашем первом снимке экрана связана с дополнительной проблемой изменения размера, добавленной Aero, и существует частичный обходной путь.

Я боролся с проблемой уродливого live-resize в нативных приложениях Win32 и создал сводку вопросов / ответов, в которой собраны 10-летние публикации о проблемах изменения размера и предложены некоторые новые идеи (слишком долго, чтобы вставить содержимое в этот вопрос). Посмотри пожалуйста:

Как сгладить уродливый джиттер / мерцание / прыжок при изменении размеров окон, особенно перетаскивая левую / верхнюю границу (Win 7-10; bg, bitblt и DWM)?

Другие вопросы по тегам