Introduction
There are times when using normal drawing methods in c# where you may want to extend those capabilities by implementing some WPF features. While WPF is good, telling people to simply switch languages is not a viable solution as somethings are better in WinForms, while some things are better in WPF.
Having a way to more naturally converge the two so you can harness the best of both methods, is not an unreasonable request.
Following is a class I whipped together to make this conversion easier.
Convert System.Drawing font to System.Windows.Media/WPF equivalent
namespace System.Drawing.WPF {
class Media {
public static class Font {
static Font() {
DrawingFont = new System.Drawing.Font("Arial", (float) 11.25);
FontStretch = new System.Windows.FontStretch();
}
public static System.Drawing.Font DrawingFont {
get;
set;
}
public static System.Windows.Media.FontFamily FontFamily {
get {
return new System.Windows.Media.FontFamily(DrawingFont.Name);
}
}
public static System.Windows.Media.FontFamily FallBackFontFamily {
get {
return new System.Windows.Media.FontFamily("Arial");
}
}
public static System.Windows.FontStyle FontStyle {
get {
return DrawingFont.Style == System.Drawing.FontStyle.Italic ? FontStyles.Italic : FontStyles.Normal;
}
}
public static System.Windows.FontWeight FontWeight {
get {
return DrawingFont.Style == System.Drawing.FontStyle.Bold ? FontWeights.Bold : FontWeights.Normal;
}
}
public static System.Windows.FontStretch FontStretch {
get;
set;
}
private static Typeface Typeface {
get {
return new Typeface(FontFamily, FontStyle, FontWeight, FontStretch, FallBackFontFamily);
}
}
}
}
}
The WPF Rabbit Hole
If, like me, you were intending on using this for WPF's
TextFormatting
methods, you should beware that most of the classes that
TextFormatting
requires, are abstract. This means that you have to write all the code by hand anyway for each of those pretty functions that WPF appears to have a method for.
While the method exists, you need to write all the code inside those methods to make them do what they claim, and in the process, delve down the rabbit hole of further required abstract classes.
On the surface, some things WPF seems to be capable of, is in fact, not capable as the code has not been written. You need to write it. I will likely get flamed or serial down-voted for stating this (even though the code solution I have provided above
ACTUALLY WORKS), however someone needs to make others aware that jumping on the bandwagon that is WPF because it is newer, or appears to have more functionality, it in fact is missing quite a few features that it claims to have due to the code not being present that would actually do said feature -- only abstract classes.
Here is a partial implementation of what I mean when delving down the TextFormatting rabbit hole. I stopped as I couldn't bear to go further. For what I needed, it was faster for me to just write the code for that than depend on TextFormatting -- which does nothing until I write the code for it anyway.
WPF Abstract class Nightmare Example
#region textformatter
class TextRunProperties : System.Windows.Media.TextFormatting.TextRunProperties {
public override Windows.Media.Brush BackgroundBrush { get; set; }
public override Windows.BaselineAlignment BaselineAlignment { get { return base.BaselineAlignment; } }
public override CultureInfo CultureInfo { get; set; }
public override double FontHintingEmSize { get; set; }
public override double FontRenderingEmSize { get; set; }
public override Windows.Media.Brush ForegroundBrush { get; set; }
public override Windows.Media.NumberSubstitution NumberSubstitution { get { return base.NumberSubstitution; } }
public override TextDecorationCollection TextDecorations { get; set; }
public override Windows.Media.TextEffectCollection TextEffects { get; set; }
public override Windows.Media.Typeface Typeface { get; set; }
public override Windows.Media.TextFormatting.TextRunTypographyProperties TypographyProperties { get { return base.TypographyProperties; } }
}
class TextRun : System.Windows.Media.TextFormatting.TextRun {
public override CharacterBufferReference CharacterBufferReference { get; set; }
public override int Length { get; set; }
public override Windows.Media.TextFormatting.TextRunProperties Properties { get; set; }
}
class TextSource : System.Windows.Media.TextFormatting.TextSource {
public override Windows.Media.TextFormatting.TextSpan<CultureSpecificCharacterBufferRange> GetPrecedingText( int textSourceCharacterIndexLimit ) {
return new TextSpan<CultureSpecificCharacterBufferRange>(
textSourceCharacterIndexLimit,
new CultureSpecificCharacterBufferRange(
new CultureInfo(0),
Windows.Media.TextFormatting.CharacterBufferRange.Empty
)
);
}
public override int GetTextEffectCharacterIndexFromTextSourceCharacterIndex( int textSourceCharacterIndex ) {
return 0;
}
public override Windows.Media.TextFormatting.TextRun GetTextRun( int textSourceCharacterIndex ) {
return new TextRun();
}
}
class TextFormatter : System.Windows.Media.TextFormatting.TextFormatter {
public override Windows.Media.TextFormatting.TextLine FormatLine( Windows.Media.TextFormatting.TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak, TextRunCache textRunCache ) {
throw new NotImplementedException();
}
public override Windows.Media.TextFormatting.TextLine FormatLine( Windows.Media.TextFormatting.TextSource textSource, int firstCharIndex, double paragraphWidth, TextParagraphProperties paragraphProperties, TextLineBreak previousLineBreak ) {
throw new NotImplementedException();
}
public override Windows.Media.TextFormatting.MinMaxParagraphWidth FormatMinMaxParagraphWidth( Windows.Media.TextFormatting.TextSource textSource, int firstCharIndex, TextParagraphProperties paragraphProperties ) {
throw new NotImplementedException();
}
public override Windows.Media.TextFormatting.MinMaxParagraphWidth FormatMinMaxParagraphWidth( Windows.Media.TextFormatting.TextSource textSource, int firstCharIndex, TextParagraphProperties paragraphProperties, TextRunCache textRunCache ) {
throw new NotImplementedException();
}
}
class TextLine : System.Windows.Media.TextFormatting.TextLine {
public override double Baseline {
get { throw new NotImplementedException(); }
}
public override int DependentLength {
get { throw new NotImplementedException(); }
}
public override double Extent {
get { throw new NotImplementedException(); }
}
public override bool HasCollapsed {
get { throw new NotImplementedException(); }
}
public override bool HasOverflowed {
get { throw new NotImplementedException(); }
}
public override double Height {
get { throw new NotImplementedException(); }
}
public override bool IsTruncated {
get {
return base.IsTruncated;
}
}
public override int Length {
get { throw new NotImplementedException(); }
}
public override double MarkerBaseline {
get { throw new NotImplementedException(); }
}
public override double MarkerHeight {
get { throw new NotImplementedException(); }
}
public override int NewlineLength {
get { throw new NotImplementedException(); }
}
public override double OverhangAfter {
get { throw new NotImplementedException(); }
}
public override double OverhangLeading {
get { throw new NotImplementedException(); }
}
public override double OverhangTrailing {
get { throw new NotImplementedException(); }
}
public override double Start {
get { throw new NotImplementedException(); }
}
public override double TextBaseline {
get { throw new NotImplementedException(); }
}
public override double TextHeight {
get { throw new NotImplementedException(); }
}
public override int TrailingWhitespaceLength {
get { throw new NotImplementedException(); }
}
public override double Width {
get { throw new NotImplementedException(); }
}
public override double WidthIncludingTrailingWhitespace {
get { throw new NotImplementedException(); }
}
public override Windows.Media.TextFormatting.TextLine Collapse( params TextCollapsingProperties[] collapsingPropertiesList ) {
throw new NotImplementedException();
}
public override void Draw( DrawingContext drawingContext, Windows.Point origin, InvertAxes inversion ) {
throw new NotImplementedException();
}
public override CharacterHit GetBackspaceCaretCharacterHit( CharacterHit characterHit ) {
throw new NotImplementedException();
}
public override CharacterHit GetCharacterHitFromDistance( double distance ) {
throw new NotImplementedException();
}
public override double GetDistanceFromCharacterHit( CharacterHit characterHit ) {
throw new NotImplementedException();
}
public override IEnumerable<IndexedGlyphRun> GetIndexedGlyphRuns() {
throw new NotImplementedException();
}
public override CharacterHit GetNextCaretCharacterHit( CharacterHit characterHit ) {
throw new NotImplementedException();
}
public override CharacterHit GetPreviousCaretCharacterHit( CharacterHit characterHit ) {
throw new NotImplementedException();
}
public override IList<TextBounds> GetTextBounds( int firstTextSourceCharacterIndex, int textLength ) {
throw new NotImplementedException();
}
public override IList<TextCollapsedRange> GetTextCollapsedRanges() {
throw new NotImplementedException();
}
public override TextLineBreak GetTextLineBreak() {
throw new NotImplementedException();
}
public override IList<TextSpan<Windows.Media.TextFormatting.TextRun>> GetTextRunSpans() {
throw new NotImplementedException();
}
}
#endregion