Исправить отображаемый мусор, оставленный диалоговым окном WPF?

В моем приложении WPF у меня есть окна WPF, которые могут открывать другие диалоговые окна WPF, что я делаю следующим образом:

PickForEveryone PickForEveryoneWindow = new PickForEveryone(sSelRecipe, selMRM.sDay, selMRM.MealTypeID);
PickForEveryoneWindow.Owner = this;
PickForEveryoneWindow.ShowDialog();

Где PickForEveryone определяется как:

public partial class PickForEveryone : Window

и

<Window x:Class="PFWb0.PickForEveryone"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
 ShowInTaskbar="False"
 Title="Pick Recipe For All" Height="536" Width="441" 
 WindowStartupLocation="CenterOwner">

И содержит сетку с DataGrid и несколько кнопок и флажков.

Который отлично работает на моих компьютерах для разработки. Однако мой клиент продолжает видеть, что диалоговые окна оставляют часть своего отображения в виде визуального мусора поверх родительского окна, когда диалоговое окно закрывается. То есть только часть окна отрисовывается, когда ShowDialog() возвращается.

Я попытался добавить this.InvalidateVisual(); ниже приведенного выше кода, но это не решило проблему.

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

Итак, я спрашиваю, знает ли кто-нибудь, как решить проблему с отображением в первую очередь или как восстановить ее, заставив WPF перерисовать окно.

Обновление: как видно из комментариев к предлагаемым ответам ниже, у меня до сих пор нет решения, которое работает на компьютерах моих клиентов, и моего обходного пути (когда окна уклоняются друг от друга) уже недостаточно. Единственное, что работает, — это минимизировать и максимизировать загрязненное основное окно.


person Dronz    schedule 18.01.2011    source источник
comment
Графические ошибки на конкретном компьютере, скорее всего, являются результатом плохого драйвера дисплея на этом компьютере. Если проблема в DirectX, то WPF может вызвать проблему, а приложение Windows Forms - нет.   -  person Martin Liversage    schedule 09.02.2011
comment
Ага. Я нашел похожие жалобы на форуме MSDN несколько лет назад, но ни у кого не было решения. Кроме того, мой клиент использует последние версии драйверов для своего видеоадаптера (что, конечно, не означает, что у него нет ошибки, но это означает, что нет простого исправления путем обновления драйверов). Кроме того, он на самом деле пытался вставить другую видеокарту, и она все еще показывала эту проблему на его машине. Я думаю, что на данный момент это может быть Vista, или, точнее, то, что вы говорите, - какие-то определенные драйверы.   -  person Dronz    schedule 10.02.2011


Ответы (5)


У меня была похожая проблема на конкретном компе с процессором ATOM N270. Проблема оказалась связана с аппаратным ускорением графики.

Чтобы отключить ускорение, просто добавьте это в реестр (это отключит аппаратное ускорение для всех приложений WPF):

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Avalon.Graphics\DisableHWAcceleration

Мне пришлось создать папку Avalon.Graphics.

DisableHWAcceleration — это DWORD, который должен быть установлен на 1.

Это решило мою проблему, если я повторно активирую ускорение, проблема вернется.

Надеюсь это поможет.

Использованная литература :

person shascoet    schedule 05.10.2012
comment
Ага! Мне очень нравится это предложение... Я попробую! - person Dronz; 09.10.2012

Этот уродливый код работает для меня:

        void RefreshWindow()
    {
        switch (WindowState)
        {
            case WindowState.Maximized:
                {
                    double oldWidth = Width;
                    Width = System.Windows.SystemParameters.PrimaryScreenWidth - 1;
                    WindowState = System.Windows.WindowState.Normal;
                    WindowState = System.Windows.WindowState.Maximized;
                    Width = oldWidth;
                }
                break;
            case WindowState.Normal:
                if (Width > 1)
                {
                    Width -= 1;
                    Width += 1;
                }
                else
                {
                    Width += 1;
                    Width -= 1;
                }
                break;
            case WindowState.Minimized:
            default:
                // no action necessary
                break;
        }
    }
person MTR    schedule 29.07.2011
comment
Хорошо, мой обходной путь перемещения окон, чтобы они не перекрывались, перерос мое приложение, которому теперь иногда требуется больше места на экране, поэтому перекрытия не так легко избежать. Итак, я собираюсь попробовать это на клиентском компьютере завтра. Спасибо за предложение МТР. Мне любопытно, сработает ли это, и я отпишусь здесь, когда узнаю. - person Dronz; 24.04.2012

Поэтому я искал ответ на этот вопрос на форумах MS, и, по-видимому, варианты этого вопроса задавались уже несколько лет.

Иногда говорят, что проблема связана с видеодрайверами, хотя в моем случае мой клиент недавно обновил свои видеодрайверы.

У меня сложилось впечатление, что Microsoft думала, что они разработали WPF так, чтобы разработчику никогда не приходилось делать такую ​​вещь, как принудительное перерисовывание дисплея, поэтому они не делают этого по дизайну. Конечно, когда что-то идет не так по какой-либо причине, это означает, что нет простого способа сделать это. И способы, которые кажутся способными это сделать (такие как InvalidateVisual()), этого не делают.

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

Код после ShowDialog:

    this.WindowState = WindowState.Minimized;
    this.WindowState = WindowState.Normal;
    this.Topmost = true;

Лучший хак выглядит примерно так:

Код снаружи:

public delegate void NoArgDelegate();

Код после ShowDialog:

    this.Dispatcher.Invoke(
    System.Windows.Threading.DispatcherPriority.Loaded,
        (NoArgDelegate)delegate {}
    );

Престо аля каззам!

person Dronz    schedule 19.01.2011
comment
Ой, видимо, это не совсем решает проблему. Если кто-нибудь знает что-нибудь, чтобы внести свой вклад в этот вопрос, пожалуйста, дайте мне знать. - person Dronz; 19.01.2011
comment
Я попробовал UpdateLayout(), но это не дало никакого эффекта. Теперь я также попытался свернуть диалоговое окно перед его закрытием. Это тоже не сработало. - person Dronz; 03.02.2011
comment
Затем я добавил код для перемещения диалогового окна в закадровые координаты, затем его минимизации, затем закрытия, и это тоже не сработало. Это изменяет анимацию ухода на моем компьютере для разработки, так что она мигает, а не сжимается, а затем исчезает, но все равно оставляет мусор в родительском окне. - person Dronz; 03.02.2011
comment
Однако мой клиент сообщает, что если он вручную перемещает диалоговое окно, оно определяет, где остается мусор, поэтому я думаю, что перемещение окна будет работать, если я смогу заставить его действительно сделать это до его закрытия. Я предполагаю, что при выполнении вызовов для изменения X и Y и минимизации, а затем закрытия вызовы позиции и минимизации не имеют эффекта до того, как закрытие вступит в силу. Как бы кто-нибудь порекомендовал мне произвести задержку или принудительно обновить визуальное окно диалогового окна перед его закрытием? - person Dronz; 03.02.2011

Это решение работает, но оно не очень красивое (легко заметить, что диалоговое окно свернуто, а затем установлено в нормальное состояние).

this.WindowState = WindowState.Minimized;
this.WindowState = WindowState.Normal;
this.Topmost = true;
person AH.    schedule 09.02.2011
comment
На самом деле ни одно из опробованных мной решений не работает на клиентском компьютере. - person Dronz; 10.02.2011
comment
Спасибо АХ. Я разместил это в своем первом ответе самому себе выше. Это должно работать (неуклюже, как это работает), но на самом деле мой клиент не запускал его. Если схема, о которой я говорил вчера, не сработает, я попрошу его попробовать. - person Dronz; 10.02.2011

До сих пор ничто из того, что я пробовал, не работало на компьютере моего клиента. У меня есть новое исправление (обходной хак) для тестирования клиента, которое включает в себя удаление окна и попытку заставить его действительно действовать, запустив пустое окно непосредственно перед закрытием диалогового окна. Вздох...

person Dronz    schedule 10.02.2011
comment
И ЭТА попытка ТОЖЕ не удалась. В конце концов, я просто избегал складывания этих окон, хотя другие окна, похоже, могут складываться, не оставляя мусора, и я понятия не имею, почему это будет проблемой, а не другие, но поскольку причина, по-видимому, является драйвером ошибка или что-то в этом роде, я думаю, я не должен ожидать слишком много логики. Обходной путь, заключающийся в том, чтобы окна не перекрывались, на самом деле является хорошим изменением дизайна, поэтому я пока отказываюсь от этой проблемы, но мне все еще любопытно, есть ли у кого-нибудь что-нибудь! - person Dronz; 03.03.2011