2

In my WPF application I have a custom Canvas implementation, in which I draw some text using a specified .ttf file. The ttf file resides in a temporary location that can be deleted at some later point in time. My problem is that once my text has been rendered on the canvas, the ttf file seems to be kept open, and can't be deleted until the application has been closed down. Is seems to be the FormattedText instance that keeps the font file open. Does anybody know a way to "Dispose" the FormattedText, or in any other way make sure that the font file is closed after rendering?

My text drawing code:

public class MyCanvas : System.Windows.Controls.Canvas
{
    protected override void OnRender(DrawingContext dc)
    {
        base.OnRender(dc);

        // Some other drawing stuff...

        FontFamily fontFamily = new FontFamily(fontUri);
        Typeface typeFace = new Typeface(fontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
        FormattedText formattedText = new FormattedText(chars, System.Globalization.CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeFace, text.FontHeight, new SolidColorBrush(color));
        dc.DrawText(formattedText, new Point(text.X + offsetX, text.Y + offsetY));
        int textWidth = (int) formattedText.Width;
        int textHeight = (int)formattedText.Height;

        // Drawing continues...
    }
}

Note: It seems I don't even have to call DrawText to lock the font file (tried commenting that line out). Using the formattedText instance to assign the textWidth and textHeight variables is enough for WPF to keep the file open.

Update: I've not been able to solve this problem, so currently I'm using a workaround that creates a new temporary font directory if overwriting the existing one fails. It works, but I'm not very happy with having to do it like this, so I'm still interested in any suggestions how to fix this.

ekholm
  • 2,543
  • 18
  • 18
  • Have you tried reworking the codea little and putting it in a "using" block? Just a guess as I haven't had to deal with fonts yet and don't have time to create a test project at the moment. – MetalMikester Jun 18 '12 at 15:56
  • Yes, I've had that in mind, but neither FormattedText, Typeface nor FontFamily implements IDisposable... – ekholm Jun 19 '12 at 06:18

1 Answers1

1

Perhaps it's related in some way to the Presentation Font Cache, a service that runs to cache font data structures so that WPF apps perform better....maybe it is keeping the file locked.

Try to change the Presentation Font Cache service so that it is Stopped and Disabled. Run your application, then try and see if you can delete the font file.

Disabling the Presentation Font Cache isn't a long term solution if it is in fact the cause. You might get away with programmatically stopping and restarting it...not sure how that would affect other running WPF applications.

There is a more definitive way to see who has the file locked, by using a tool e.g.

A possible solution (to get around whoever is locking the file) is to put the .TTF file as a Resource in your application, then you can let WPF worry about how to manage and clean it up.

Links:

UPDATE:

You could create a wrapper class whose job is to delete a file when the object is disposed or if it can't delete the file at dispose time because the file is still locked, then it will get deleted when the Garbage Collector calls the Finalizer.

Another possiblity is to use FileOptions.DeleteOnClose - you'd have to see if it was possible to use FontFamily on a font file that you opened/created and are currently maintaining an open file handle on.

You say "The ttf file resides in a temporary location that can be deleted at some later point in time."...when you say at some later point in time...I'm presuming it's when you exit the program/process....or is that not the case?

or try TempFileCollection:

Community
  • 1
  • 1
Colin Smith
  • 12,375
  • 4
  • 39
  • 47
  • Thanks for the suggestion, but that does not seem to be the problem in my case. Actually I can't even find the Presentation Font Cache service on my system (XP and .NET 4.0). I checked with Process Explorer and it is my application process that keeps the font file open. I can't embed the ttf file in my application, because fonts needs to be dynamically added and removed by the users. – ekholm Jul 30 '12 at 07:46
  • The font files in my case are packed together with other files into a configuration file that can be opened and saved by the application. Each time a config is opened, it is extracted to a temporary working folder. That folder needs to be cleaned when a new config is loaded. So the timing is important, which means I can't rely on the GC, and I don't want to delete the ttf file when closed (cause it's not closed until the app closes). Also tried out TempFileCollection, but not surprisingly it cannot delete the locked files either. – ekholm Jul 31 '12 at 07:08
  • My current workaround creates a new working dir when needed, and all working dirs can be deleted the next time the app starts. The normal use case for the app is as a wizard to open one single config, edit and save it and then close the app. The configurations are not extremely large either, so it is not such a big deal actually. I'll give you an upvote though for your efforts and nice links. – ekholm Jul 31 '12 at 07:09