Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF analogy for 'em' unit

What is the WPF analogy for the CSS em unit?

like image 847
alex2k8 Avatar asked Mar 17 '09 11:03

alex2k8


4 Answers

Here is what I did. Created a MarkupExtension that converts Font size to EM based on font assigned on Window.

I would like to thank http://10rem.net/blog/2011/03/09/creating-a-custom-markup-extension-in-wpf-and-soon-silverlight

and

http://tomlev2.wordpress.com/tag/markup-extension/

for providing required knowledge.

[MarkupExtensionReturnType(typeof(double))]
public class EmFontSize : MarkupExtension
{
    public EmFontSize() { }

    public EmFontSize(double size)
    {
        Size = size;
    }

    [ConstructorArgument("size")]
    public double Size { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (serviceProvider == null)
            return null;

        // get the target of the extension from the IServiceProvider interface
        IProvideValueTarget ipvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
        if (ipvt.TargetObject.GetType().FullName == "System.Windows.SharedDp")
            return this;

        DependencyObject targetObject = ipvt.TargetObject as DependencyObject;

        var window = TryFindParent<Window>(targetObject);
        if (window != null)
        {
            return window.FontSize * Size;
        }
        return 12 * Size;
    }

    public static T TryFindParent<T>(DependencyObject child) where T : DependencyObject
    {
        //get parent item
        DependencyObject parentObject = GetParentObject(child);

        //we've reached the end of the tree
        if (parentObject == null) return null;

        //check if the parent matches the type we're looking for
        T parent = parentObject as T;
        if (parent != null)
        {
            return parent;
        }
        else
        {
            //use recursion to proceed with next level
            return TryFindParent<T>(parentObject);
        }
    }

    public static DependencyObject GetParentObject(DependencyObject child)
    {
        if (child == null) return null;

        //handle content elements separately
        ContentElement contentElement = child as ContentElement;
        if (contentElement != null)
        {
            DependencyObject parent = ContentOperations.GetParent(contentElement);
            if (parent != null) return parent;

            FrameworkContentElement fce = contentElement as FrameworkContentElement;
            return fce != null ? fce.Parent : null;
        }

        //also try searching for parent in framework elements (such as DockPanel, etc)
        FrameworkElement frameworkElement = child as FrameworkElement;
        if (frameworkElement != null)
        {
            DependencyObject parent = frameworkElement.Parent;
            if (parent != null) return parent;
        }

        //if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
        return VisualTreeHelper.GetParent(child);
    }
}

Sample Usage

xmlns:my="clr-namespace:FontSizeExample"
<TextBlock Text="Sample Font" FontSize="{my:EmFontSize 1.1}"/>
<TextBlock Text="Sample Font" FontSize="{my:EmFontSize .9}"/>
like image 161
Ashish Avatar answered Oct 21 '22 05:10

Ashish


em size is the width of the uppercase letter M in the current font, there is no font-dependent sizing method in Wpf

Btw, WPF uses "device independent pixels" that are always 1/96 of an inch (because that's one pixels on today's monitors) so:

  • 1 pixel is 1/96 inches
  • 96 pixels in an inch
  • 1.33333 pixels is a point
  • 3.779 pixels is a mm

Those are extremely inaccurate on monitors because almost all monitors report a 96DPI resolution and ignore the real pixel size, but are very useful when printing.

like image 29
Nir Avatar answered Oct 21 '22 06:10

Nir


<ScaleTransform ScaleX="1.2" ScaleY="1.2"></ScaleTransform> 

seems to be more or less the 1.2em alternative.

like image 3
alex2k8 Avatar answered Oct 21 '22 05:10

alex2k8


AFAIK, there isn't one right now. But you can make your desire for this known here.

One alternative (and I don't know if this is possible either) would be to measure how big the desired font is, then take that as your "ems" unit, then scale using those "units" instead.

like image 2
John Feminella Avatar answered Oct 21 '22 06:10

John Feminella