What is the WPF analogy for the CSS em unit?
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}"/>
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:
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.
<ScaleTransform ScaleX="1.2" ScaleY="1.2"></ScaleTransform>
seems to be more or less the 1.2em alternative.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With