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

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

Screenshot of described artifacts

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

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

ОБНОВЛЕНИЕ: IЯ нашел несколько других связанных ресурсов по этой проблеме, которыми, я думал, я должен поделиться.

Ответы [ 4 ]

8 голосов
/ 07 апреля 2010

Похоже, что еще один обходной путь - вернуться к программному рендерингу, а не использовать преимущества аппаратного ускорения. Это было предложение Марко Чжоу на форумах 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, о котором я писал ранее. На данный момент я планирую использовать свое исходное решение Refresh для MDI Parent для моего проекта WinForms, но затем для других моих собственных приложений взаимодействия, например, когда мои элементы управления WPF размещены в Visual FoxPro, я буду использовать это решение. Это, конечно, если не будет найдено более элегантное решение для любого из случаев.

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

2 голосов
/ 17 января 2013

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

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

У меня была похожая проблема, проверка настроек моей видеокарты (NVidia Control Panel) показала очень высокий уровень глобальных настроек, что приводит к увеличению интервала обновления, который может быть прерван, если потребуется слишком много времени.Сброс моих настроек до значений по умолчанию решил большую часть проблемы.Но я также запускаю программы хеширования, которые интенсивно используют графический процессор, так что это, вероятно, является причиной моей остающейся проблемы с артефактами, которая сейчас встречается очень редко и в основном показывает свое уродливое лицо в Visual Studio.чтобы отключить аппаратное ускорение для WPF, это можно сделать в «HKEY_CURRENT_USER / SOFTWARE / Microsoft / Avalon.Graphics», или, может быть, приложение может сделать это, НО это только для устранения неполадок;никогда не устанавливайте их в приложении, потому что это отключит для ВСЕХ приложений WPF.У меня нет этого параметра реестра и я не добавил его, поэтому я не уверен в успехе с ним, но многие говорят, что это решило их проблему.Также обратите внимание, что в некоторых приложениях эта опция доступна, попробуйте отключить ее, если она доступна.

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

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

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

Надеюсь, это кому-нибудь поможет.

- Райан Страсбург

2 голосов
/ 07 апреля 2010

Ну, я мог бы найти решение, хотя это похоже на взлом. Похоже, что если вы вызываете метод Refresh для родителя MDI, когда перемещается дочерняя форма 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 () , Invalidate () , Refresh () , а также я попробовал эти же методы на родительском объекте MDI, а также Dispatcher.Invoke (DispatcherPriority.Render, ...) и InvalidateVisual () на моем размещенном элементе управления WPF, но ни один из этих других методов не работает, примите для вызова Refresh () специально для родителя MDI.

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

0 голосов
/ 25 августа 2015

Ваше пользовательское управление или событие загрузки окна;

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...