WPF FormattedText “The system cannot find the file specified” exception in a service

不想你离开。 提交于 2019-12-06 15:57:22

As you already know from the info you provided, All UI elements (FormattedText is one) have to be created on the UI thread.

The code you are looking for is:

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 };
      }));

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)

A shot in the dark:

The stack trace seems to show that WPF does not find a Dispatcher in the thread executing GetTextSize, so it has to create a new one, which involves creating a handle to a window.

Calling this every 10 seconds means 8'640 threads, thus windows per day. According to Mark Russinovich, there is a limit of 32 K windows per session, which may explain the error in RegisterClassEx.

An idea to overcome this is to read the current dispatcher from your main thread and set it in your tasks.

Edit: I had another look and it looks like one cannot set the Dispatcher of a thread (it's created automatically).

I'm sorry, I am unable to understand what is going on here.

In order to compute the text size, WPF needs a FormattedText instance, which is stored as a member of the Dispatcher class. The existing Dispatchers are stored in a list of weak references. Each one is associated with a specific thread. Here, it looks like new Dispatcher instances are created many, many times. So, either the calling thread is new or memory is quite low and the weak references have been discarded. The first case (new thread) is unlikely as the task scheduler uses the thread pool, which has about 25 threads per core (if I remember correctly), which is not enough to deplete the pool of ATOMs or windows. In the second case, the depletion of resource is unlikely as the HwndWrapper is IDisposable and the Dispose method takes care of freeing the registered class.

Shiraz Bhaiji

Have you renamed anything? If yes, check that link: WPF Prism: Problem with creating a Shell

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!