Мы используем объект WPF FormattedText для определения размера текста в службе, которая получает заголовки последних новостей из RSS-канала.Полученный текст должен быть в указанном размере холста.Служба запускает код каждые 10 секунд и использует до 2 потоков, если один занимает больше времени.Я использую TaskFactory (который я переопределил LimitedConcurrencyLevelTaskScheduler, чтобы ограничить количество потоков, которые я указал).
Это прекрасно работает, за исключением того, что через несколько дней (длина переменная), мы начинаем получатьследующие исключения.Тот же код работал нормально до того, как мы начали использовать TPL, чтобы сделать его многопоточным.
Мне нужна помощь, чтобы выяснить, чем это вызвано.Несколько мыслей, которые я изучаю: коллизии потоков, удерживающие файл TTF, проблема с памятью, диспетчер (см. Трассировку стека) не очень хорошо играет с TaskFactory, другие ??У нас нет хорошей настройки профилирования, но мы посмотрели на TaskManager, когда возникает исключение и использование памяти выглядит нормально.Моя следующая попытка - использовать объект TextBlock и посмотреть, будет ли исключение исключено.
Сообщение об ошибке: системе не удается найти указанный файл. Источник ошибки: Целевой сайт ошибки WindowsBase: UInt16 RegisterClassEx (WNDCLASSEX_D)
Трассировка стека исключений:
в MS.Win32.UnsafeNativeMethods.RegisterClassEx (WNDCLASSEX_D wc_d) в MS.Win32.HwndWrapper..ctor (Int32 classStyle, стиль Int32, Int32 exStyle, Int32 x, Int32 y,ширина, высота Int32, имя строки, родительский элемент IntPtr, хуки HwndWrapperHook []) в System.Windows.Threading.Dispatcher..ctor () в System.Windows.Threading.Dispatcher.get_CurrentDispatcher () в System.Windows.Media.TextFormatting.TextFormatter.FromCurrentDispatcher (TextFormattingMode textFormattingMode) в System.Windows.Media.FormattedText.LineEnumerator..ctor (FormattedText text) в System.Windows.Media.FormattedText.DrawAndCalculateMetrics..FormattedText.get_Metrics () at (мой метод использует FormattedText, который находится в цикле)
private static Size GetTextSize(string txt, Typeface tf, int size)
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}
EDIT: до сих пор я пытался установить блокировку вокруг кода, вызывающего эту функцию, и вызвать его внутриCurrentDispatcher.Invoke метод, например, так:
return (Size)Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
FormattedText ft = new FormattedText(txt, new CultureInfo("en-us"), System.Windows.FlowDirection.LeftToRight, tf, (double)size, System.Windows.Media.Brushes.Black, null, TextFormattingMode.Display);
return new Size { Width = ft.WidthIncludingTrailingWhitespace, Height = ft.Height };
}));
РЕДАКТИРОВАТЬ: я нашел ссылки на других, имеющих похожие, но не точную проблему.http://www.eggheadcafe.com/software/aspnet/31783898/problem-creating-an-bitmapsource-from-an-hbitmap-in-threaded-code.aspx ~ есть похожая проблема, но нет ответов
System.Windows.Media.DrawingVisual.RenderOpen () выдает ошибку через некоторое время ~ возникла похожая проблема, но нетответы
http://connect.microsoft.com/VisualStudio/feedback/details/361469/net-3-5-sp1-breaks-use-of-wpf-under-iis# ~ аналогичное исключение, но мы не используем 3.5SP1 или IIS 7.
Я также отправил это через сайт Microsoft Connect (проголосуйте заэто если у вас возникла похожая проблема).https://connect.microsoft.com/WPF/feedback/details/654208/wpf-formattedtext-the-system-cannot-find-the-file-specified-exception-in-a-service
РЕДАКТИРОВАТЬ: Ответ от Microsoft: «Объекты WPF должны создаваться в потоках Dispatcher, а не в потоках пула потоков. Обычно мы рекомендуем выделять поток для запуска цикла диспетчера для запросов на обслуживание для создания объектов иверните их замороженными. Спасибо, WPF Team "~ Как бы я это реализовал?
РЕДАКТИРОВАТЬ: окончательное решение благодаря NightDweller
if(Application.Current == null) new Application();
(Size)Application.Current.Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
...});
РЕДАКТИРОВАТЬ: Когда я внедрил изменения (новое приложение ();), Я получил сообщение об ошибке «Невозможно создать более одного экземпляра System.Windows.Application в одном домене приложений».Источник ошибки: Ошибка PresentationFramework Целевой сайт: Void .ctor ()