问题描述
我们正在使用WPF FormattedText对象来确定服务中的文本大小,该服务从RSS提要中获取最新新闻标题.检索到的文本必须使用指定的画布大小.该服务每10秒运行一次代码,如果一个线程花费的时间更长,则最多使用2个线程.我正在使用TaskFactory(已重写LimitedConcurrencyLevelTaskScheduler以限制到我指定的线程数量).
We are using the WPF FormattedText object to determine text size in a service that grabs the latest news headlines from an RSS feed. The text retrieved needs to be in a specified canvas size. The service runs the code every 10 seconds and uses up to 2 threads if one takes longer than that. I'm using TaskFactory (which I've overridden the LimitedConcurrencyLevelTaskScheduler to limit to the amount of threads I specified).
这很好用,除了几天(长度是可变的)之后,我们开始遇到以下异常.在我们开始使用TPL使其成为多线程之前,相同的代码运行良好.
This works great, except after several days (the length is variable), we start to get the following exceptions. The same code was working fine before we started using TPL to make it mult-threaded.
我需要帮助弄清楚这是由什么引起的.我正在研究的一些想法是:持有TTF文件的线程冲突,内存问题,分派器(请参阅堆栈跟踪)与TaskFactory的配合不好,其他?我们没有很好的性能分析设置,但是当异常发生并且内存使用看起来正常时,我们已经查看了TaskManager.我的下一个尝试是使用TextBlock对象,并查看是否避免了该异常.
I need help figuring out what this is caused by. A few thoughts I'm looking into are: thread collisions holding on to a TTF file, memory issue, the dispatcher (see the stack trace) isn't playing nicely with the TaskFactory, other??We don't have good profiling setup, but we've looked at the TaskManager when the exception is occurring and memory usage looks normal.My next attempt is to use the TextBlock object and see if the exception is avoided.
错误信息:系统找不到指定的文件错误源:WindowsBase错误目标站点:UInt16 RegisterClassEx(WNDCLASSEX_D)
Error Message: The system cannot find the file specifiedError Source: WindowsBaseError Target Site: UInt16 RegisterClassEx(WNDCLASSEX_D)
在MS.Win32.HwndWrapper..ctor中(Int32 classStyle,Int32样式,Int32 exStyle,Int32 x,Int32 y,Int32宽度,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文本) 在System.Windows.Media.FormattedText.DrawAndCalculateMetrics(DrawingContext dc,Point drawingOffset,Boolean getBlackBoxMetrics) 在System.Windows.Media.FormattedText.get_Metrics() 在(我的方法使用处于循环中的FormattedText)
at MS.Win32.UnsafeNativeMethods.RegisterClassEx(WNDCLASSEX_D wc_d) at MS.Win32.HwndWrapper..ctor(Int32 classStyle, Int32 style, Int32 exStyle, Int32 x, Int32 y, Int32 width, Int32 height, String name, IntPtr parent, HwndWrapperHook[] hooks) at System.Windows.Threading.Dispatcher..ctor() at System.Windows.Threading.Dispatcher.get_CurrentDispatcher() at System.Windows.Media.TextFormatting.TextFormatter.FromCurrentDispatcher(TextFormattingMode textFormattingMode) at System.Windows.Media.FormattedText.LineEnumerator..ctor(FormattedText text) at System.Windows.Media.FormattedText.DrawAndCalculateMetrics(DrawingContext dc, Point drawingOffset, Boolean getBlackBoxMetrics) at System.Windows.Media.FormattedText.get_Metrics() at(my method using the FormattedText, which is in a loop)
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 };
}
到目前为止,我已经尝试在调用此函数的代码周围放置一个锁,并像下面这样在CurrentDispatcher.Invoke方法中调用它:
so far I've tried placing a lock around the code that calls this function, and calling it inside the CurrentDispatcher.Invoke method like so:
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 〜遇到类似的问题,但没有答案
I've found links to others having similar, but not the exact problem.http://www.eggheadcafe.com/software/aspnet/31783898/problem-creating-an-bitmapsource-from-an-hbitmap-in-threaded-code.aspx ~having a similar problem, but no answers
System.Windows.Media.DrawingVisual.RenderOpen()一段时间后出错〜有类似的问题,但没有答案
System.Windows.Media.DrawingVisual.RenderOpen() erroring after a time ~having a similar problem, but no answers
http://connect.microsoft.com/VisualStudio/feedback/details/361469/net-3-5-sp1-breaks-use-of-wpf-under-iis# 〜类似的异常,但是我们没有使用3.5SP1或IIS 7.
http://connect.microsoft.com/VisualStudio/feedback/details/361469/net-3-5-sp1-breaks-use-of-wpf-under-iis# ~ similar exception, but we're not using 3.5SP1 or 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
I've also submitted this through the Microsoft Connect site (please vote for it if you are having a similar problem).https://connect.microsoft.com/WPF/feedback/details/654208/wpf-formattedtext-the-system-cannot-find-the-file-specified-exception-in-a-service
来自Microsoft的回复:"WPF对象需要在分派器线程上创建,而不是在线程池线程上创建.我们通常建议使用专用线程来运行分派器循环,以服务于创建对象并返回的请求他们冻结了.谢谢,WPF团队〜我将如何实现呢?
Response from Microsoft:"WPF objects need to be created on Dispatcher threads, not thread-pool threads. We usually recommend dedicating a thread to run the dispatcher loop to service requests to create objects and returnthem frozen. Thanks, WPF Team" ~ How would I implement this?
归功于NightDweller
final solution thanks to NightDweller
if(Application.Current == null) new Application();
(Size)Application.Current.Dispatcher.CurrentDispatcher.Invoke(new Func<Size>(() =>
{
...});
部署更改(新Application();)时,记录了错误无法在同一AppDomain中创建多个System.Windows.Application实例".错误源:PresentationFramework错误目标网站:Void .ctor()
When I deployed the change (new Application();), I got an error logged " Cannot create more than one System.Windows.Application instance in the same AppDomain."Error Source: PresentationFrameworkError Target Site: Void .ctor()
推荐答案
从提供的信息中已经知道,必须在UI线程上创建所有UI元素(FormattedText是其中之一).
As you already know from the info you provided, All UI elements (FormattedText is one) have to be created on the UI thread.
您要查找的代码是:
return (Size)Application.Current.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 };
}));
注意 Application.Current -您需要应用程序"调度程序,它是WPF应用程序中UI线程的调度程序.您当前的代码实际上为当前线程创建了一个调度程序,因此您并没有真正更改执行线程(请参阅此处关于调度程序)
Notice the Application.Current - you want the "Application" dispatcher which is the dispatcher for the UI thread in WPF applications.Your current code actually creates a dispatcher for the current thread so you didn't really change the executing thread (see here regarding the dispatcher)
这篇关于WPF FormattedText“系统找不到指定的文件".服务中的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!