How to specify WPF control size in millimeters using XAML

The first thing that we need to do to use millimeters in XAML is to define simple Mm2PixelConverter class that performs the conversion from millimeter to pixels:

[ValueConversion(typeof(double), typeof(double))]
class Mm2PixelConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        double mm = (double)value;

        return WinUtil.Mm2Pixel(mm);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

Then to specify WPF control width and height using our simple converter we need to use binding in XAML. At first I tried to define width and height in millimeters using control resources as shown below:

<UserControl x:Class="VirtuePrint.Paper.SmallPackageLableCell"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             xmlns:local="clr-namespace:VirtuePrint.Paper"
             xmlns:converters="clr-namespace:VirtuePrint.Converters"
             mc:Ignorable="d" 
             Width="{Binding Source={StaticResource mmWidth}, Converter={StaticResource mm2PixelConverter}}"
             Height="{Binding Source={StaticResource mmHeight}, Converter={StaticResource mm2PixelConverter}}"
             ...
             >
    <UserControl.Resources>
        <converters:Mm2PixelConverter x:Key="mm2PixelConverter" />
        <sys:Double x:Key="mmWidth">170</sys:Double>
        <sys:Double x:Key="mmHeight">95</sys:Double>
        ...
    </UserControl.Resources>
    ...
</UserControl>

It worked fine at design time, but at runtime I got XamlParseException with inner exception message “Cannot find resource named ‘mmWidth’. Resource names are case sensitive.”. This probably means that control resources does not exist at the stage of defining control with and height so I declared DefaultInstance of the convertor, got rid of resources and rewritten this code as follows:

<UserControl x:Class="VirtuePrint.Paper.SmallPackageLableCell"
             ...
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             xmlns:local="clr-namespace:VirtuePrint.Paper"
             xmlns:converters="clr-namespace:VirtuePrint.Converters"
             >
    <UserControl.Width>
        <Binding Converter="{x:Static converters:Mm2PixelConverter.DefaultInstance}">
            <Binding.Source>
                <sys:Double>170</sys:Double>
            </Binding.Source>
        </Binding>
    </UserControl.Width>
    <UserControl.Height>
        <Binding Converter="{x:Static converters:Mm2PixelConverter.DefaultInstance}">
            <Binding.Source>
                <sys:Double>95</sys:Double>
            </Binding.Source>
        </Binding>
    </UserControl.Height>
...
</UserControl>

Below I provided the source code of WinUtil class used to convert millimeters to pixels:

public static class WinUtil
{
    public static double Mm2Pixel(double mm)
    {
        const double factor = 96 / 25.4;

        return mm * factor;
    }

    public static Size Mm2Pixel(Size mm_size)
    {
        return new Size(Mm2Pixel(mm_size.Width), Mm2Pixel(mm_size.Height));
    }
}

Finally I realized that XAML supports “qualified double” and I can specify width and height in centimeters:

<local:CellControl x:Class="VirtuePrint.Paper.SmallPackageLableCell"
             ...
             Width="17.0cm"
             Height="9.5cm"
             >

Leave a Reply

Your email address will not be published. Required fields are marked *