Как избежать визуальных артефактов при размещении пользовательских элементов управления WPF в приложении WinForms MDI?

при размещении пользовательских элементов управления WPF в приложении WinForms MDI возникает проблема рисования, когда у вас есть несколько форм, которые перекрывают друг друга, что вызывает очень разные визуальные артефакты. Эти артефакты в основном видны после перетаскивания одной дочерней формы поверх другой, в которой также размещается содержимое WPF, или путем обрезки ребер дочерней формы основным родителем MDI при перетаскивании. После завершения перетаскивания дочерней формы артефакты остаются в целом но я обнаружил, что установка фокуса на окно другого приложения, а затем перефокусировка на мое окно приложения, что оно перерисовывается, и все хорошо снова, пока дочерние формы не будут перемещены еще раз. См. изображение ниже, которое демонстрирует проблему.

Screenshot of described artifacts

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

обновление: несколько дополнительных замечаний, которые я пропустил, заключается в том, что если я создаю эти формы без установки MdiParent, они создаются как обычные формы, и эта проблема не возникает. Эта проблема кажется уникальной для сценария MDI WinForms. Кроме того, в настоящее время я работаю на Windows 7 Enterprise, и я знаю, что результаты могут быть совершенно разными в Windows XP, Но я не смог протестировать этот.

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

4 ответов


похоже, что другой обходной путь-вернуться к программному рендерингу, а не использовать аппаратное ускорение. Это был предложение Марко Чжоу на форумах MSDN.

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
        this.Loaded += delegate
        {
            var source = PresentationSource.FromVisual(this);
            var hwndTarget = source.CompositionTarget as HwndTarget;
            if (hwndTarget != null)
            {
                hwndTarget.RenderMode = RenderMode.SoftwareOnly;
            }
        };
    }
}

я протестировал это, и это решение, похоже, работает очень хорошо, и до сих пор это единственное решение, которое я нашел для решения этой проблемы в сценарии взаимодействия FoxPro, который очень похож на WinForms, о котором я написал изначально. Сейчас я планирую используйте мое исходное обновление родительского решения MDI для моего проекта WinForms, но затем для других моих собственных приложений взаимодействия, таких как, когда мои элементы управления WPF размещены в Visual FoxPro, я буду использовать это решение. Это, конечно, если не будет найдено более элегантное решение для любого из случаев.

также важно отметить, что из того, что я знаю, программный рендеринг является единственным вариантом в системах XP, и обычно Visual FoxPro Nore WinForms обычно использует то же самое тип аппаратного ускорения, которое делают собственные приложения WPF в ОС Vista и выше. Поэтому использование этой опции может быть не так плохо, как кажется, когда вам приходится иметь дело с interop. В настоящее время я не знаю о каких-либо побочных эффектах при использовании этого решения, но если они есть, их нужно будет серьезно рассмотреть.


Ну, я, возможно, нашел решение, хотя это похоже на немного взломать. Похоже, что при вызове метода Refresh для MDI-родителя whenver перемещается дочерняя форма MDI, отмеченные артефакты исчезают. Визуально вещи кажутся немного нервными при перетаскивании окна, но это кажется гораздо более приемлемым, чем пример, который я показал в своем исходном посте.

private void Form1_Move(object sender, EventArgs e)
{
    this.ParentForm.Refresh();

    System.Diagnostics.Debug.WriteLine(string.Format("Form Moved to: ({0},{1})", this.Left, this.Top));
}

Я пробовал много комбинаций в том же духе, таких как обновление только дочернего окна, которое перемещалось вызывающие методы, такие как Update (), недействительными(), обновить() а также я пробовал эти же методы на родителе MDI, а также диспетчер.Invoke (DispatcherPriority.Оказывать. ,..) и InvalidateVisual() на моем размещенном элементе управления WPF, но ни один из этих других методов не работал принять вызов обновить() конкретно на родителе MDI.

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


Проверьте видео-драйверы и попробуйте отключить аппаратное ускорение. Большинство артефактов вызваны плохими драйверами, сбоем видеокарты или недостаточным временем для завершения обновления.

первый шаг устранения неполадок: обновление видеодрайверов. Очевидно, я знаю.

У меня была аналогичная проблема, проверка настроек видеокарты (Панель управления NVidia) показала, что глобальный набор настроек очень высок, вызывая более длительный интервал обновления, который может быть прерван, если займет слишком много времени. Установка моих настроек обратно в по умолчанию решена большая часть проблемы. Но я также запускаю программы хэширования, которые интенсивно используют GPU, поэтому это, вероятно, причина моей проблемы артефакта remaing, которая сейчас очень редко и в основном показывает свое уродливое лицо в Visual Studio.

еще один шаг по устранению неполадок, с которым я столкнулся, - отключить аппаратное ускорение для WPF, это можно сделать в " HKEY_CURRENT_USER/SOFTWARE/Microsoft/Avalon.Графика", или, может быть, приложение может это сделать, но это только для устранения неполадок; никогда не устанавливайте их в приложении, потому что он будет отключен для всех приложений WPF. У меня нет этого параметра реестра, и я не добавил его, поэтому я не уверен в успехе, но многие говорят, что это решило их проблему. Также обратите внимание, что некоторые приложения имеют эту опцию, попробуйте отключить ее, если она доступна.

другой шаг устранения неполадок - убедиться, что видеокарта является надлежащим уровнем уровня для рендеринга. Любая карта, которая поддерживает DX9 или выше, должна быть достаточной, но задействованы другие факторы (как и в моем случае) так что только потому, что он находится в списке, не означает, что он подходит для вашей цели.

наконец, вы можете использовать Visual Profiler (часть Windows SDK) и другие инструменты, чтобы помочь определить, что происходит более точно с WPF, не хватает производительности по отношению к графической способности.

Примечания уровня отрисовки и сведения о производительности WPF --> http://msdn.microsoft.com/en-us/library/vstudio/ms742196 (v=против 90).aspx

Надежда это кому-то помогает.

--Ryan Strassburg


ваше событие usercontrol или window loaded;

this.WindowState = System.Windows.WindowState.Minimized;

this.WindowState = System.Windows.WindowState.Normal;

это может показаться плохим решением. не нужно биться головой о стену.

турецкая пословица гласит: лучший код-это код, который работает:)