WPF: How to specify units in Dialog Units?
Asked Answered
C

5

24

i'm trying to figure out how to layout a simple dialog in WPF using the proper dialog units (DLUs).


What's a dialog unit?


A dialog is a unit of measure based on the user's preferred font size. A dialog unit is defined such that the average character is 4 dialog units wide by 8 dialog units high:

enter image description here

This means that dialog units:

  • change with selected font
  • changed with selected DPI setting
  • are not square

i spent about two hours dimensioning this sample dialog box from Windows Vista with the various dlu measurements. Can someone please give the corresponding XAML markup that generates this dialog box?

alt text

(Image Link)

Now admittedly i know almost nothing about WPF XAML. Every time i start, i get stymied because i cannot figure out how to place any control. It seems that everything in WPF must be contained on a panel of some kind. There's StackPanels, FlowPanels, DockPanel, Grid, etc. If you don't have one of these then it won't compile.

The only XAML i've been able to come up with (uing XAMLPad) so far:

<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Image Width="23" />
    <Label>Are you sure you want to move this file to the Recycle Bin?</Label>
    <Image Width="60" />
    <Label>117__6.jpg</Label>
    <Label>Type: ACDSee JPG Image</Label>
    <Label>Rating: Unrated</Label>
    <Label>Dimensions: 1072 × 712</Label>
    <Button Content="Yes" Width="50" Height="14"/>  
    <Button Content="Cancel" Width="50" Height="14"/>  
</DockPanel>

Which renders as a gaudy monstrosity. None of the controls are placed or sized right. i cannot figure out how to position controls in a window, nor size them properly.

Can someone turn that screenshot into XAML?

Note: You're not allowed to measure the screenshot. All the Dialog Unit (dlu) widths and heights are specified.

Note: 1 horizontal DLU != 1 vertical DLU. Horizontal and vertical DLUs are different sizes.


See also

Bump: 6/20/2011

Cow answered 27/12, 2008 at 17:37 Comment(0)
I
8

The following XAML will give you the effect you are looking for.

Note that I have doubled the DLU units in the markup - thus keeping the same aspect. It looked funny having a Button height of 14units. You may need to tinker with the figures presented in the market.

Also, I started to remove some of the "Vista Layout" into separate styles. You may be able to continue down this path so you have quite a reusable set of styles which follow the Vista guidelines. I'm fairly sure some other people have done something similar.

Furthermore, I took some liberties with the size of the dialog. You mentioned you wanted 210x96units - you would need to set this amount, plus the window chrome.

Anyway, on with the content:

  <Window x:Class="VistaLayout.Dialog"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="Delete File" 
      ResizeMode="NoResize"
      Height="212" Width="430">
    <Window.Resources>
      <Style x:Key="FooterButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="Width" Value="100" />
        <Setter Property="Height" Value="28" />
        <Setter Property="Margin" Value="8,0,0,0" />
      </Style>
      <Style x:Key="FooterPanelStyle" TargetType="{x:Type UniformGrid}">
        <Style.Resources>
          <Style TargetType="{x:Type Button}" BasedOn="{StaticResource FooterButtonStyle}" />
        </Style.Resources>
        <Setter Property="Rows" Value="1" />
        <Setter Property="HorizontalAlignment" Value="Right" />
      </Style>
    </Window.Resources>
    <DockPanel Margin="14">
      <!-- Footer -->
      <UniformGrid DockPanel.Dock="Bottom" 
                       Style="{StaticResource FooterPanelStyle}">
        <Button>_Yes</Button>
        <Button>_No</Button>
      </UniformGrid>

      <!-- Main Content -->
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto" />
          <ColumnDefinition Width="8" />
          <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <Image Width="64" />

        <StackPanel Grid.Column="2">
          <TextBlock Margin="0,6,0,14">Are you sure you want to move this file to the Recycle Bin?</TextBlock>

          <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="Auto" />
              <ColumnDefinition Width="14" />
              <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Image Width="60" />

            <StackPanel Grid.Column="2">
              <TextBlock>117__6.jpg</TextBlock>
              <TextBlock>Type: ACDSee JPG Image</TextBlock>
              <TextBlock>Rating: Unrated</TextBlock>
              <TextBlock>Dimensions: 1072 × 712</TextBlock>
            </StackPanel>

          </Grid>

        </StackPanel>

      </Grid>

    </DockPanel>
  </Window>

As with most XAML, this could be done in a myriad of ways - this is only one solution.

Hope this helps!

Intermigration answered 28/12, 2008 at 3:46 Comment(5)
Where are you getting the width and height values from? Will those numbers scale with the user's Windows font preferences? As i understand it, any lengths specified without units are understood to be "logical pixels" where 1 logical pixel is 1/96 of an inch.Cow
XamlPad cannot show you <Window> thingies, and ie will choke on <Window> thingies due to some security blah. So i can't view it anyway.Cow
Are you developing an Xdap application? If so, you will need to change the Window to userControl. This class assumes a code-behind file. Try creating a new UserControl, and copying over the XAML. Replace Window with UserControl. You will of course have to update the x:Class name.Intermigration
The window will scale with the user's DPI preference, but not necessarily their Font preference. This xaml doesn't respect the user's font selection - It uses Segeo UI I belive as standard (although I could be wrong).Intermigration
I did some investigation into DLUs - which seem to be based around the size of the font. WPFs layout system is based on Device-Independent-Units. I don't know of a way to use DLUs in WPF. That said the layout presented should give you a good starting point in creating a dialog that sizes reasonably.Intermigration
S
2

I know this is very old, but I thought I would attempt to do what the OP asked. And as such this is my attempt. BTW, before I continue, I should point out that for some reason, the OPs measurements didn't quite work out when using DLUs, but I think I've come reasonably close. Also please keep in mind I'm still a relative n00b when it comes to this stuff... so if I've done something wrong or blasphemous... apologies.

Final Result

First I had to find a way to get the width and height of a given letter of a given font (In my case, Segoe UI at 10px)... which for that I used this SO answer: how-to-calculate-wpf-textblock-width-for-its-known-font-size-and-characters to which I made a static class to hold the resulting doubles:

public static class Fonts
{
    public static double HorizontalDluMultiplier;
    public static double VerticalDluMultiplier;

    static Fonts()
    {
        var formattedText = new FormattedText(
            "A",
            CultureInfo.CurrentUICulture,
            FlowDirection.LeftToRight,
            new Typeface("Segoe UI"),
            12.0,
            Brushes.Black);
        Fonts.HorizontalDluMultiplier = formattedText.Width / 4;
        Fonts.VerticalDluMultiplier = formattedText.Height / 8;
    }
}

Once I had the metrics I had to create a WPF converter that takes a given ConverterParameter (In this case a number in DLUs) and spits out a double of pixels. This is the converter I used...

public class HorizontalDluToPixelConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (Double.Parse((parameter as string))) * Fonts.HorizontalDluMultiplier;
    }

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

I think it goes without saying that I had a seperate Vertical version of the converter.

Once that was done, I was just a matter of laying out the window in XAML and when it came to setting heights and widths, using the converter. I used a single grid to lay out the entire window. but to set the column widths and row heights I used the converter like so:

<Window.Resources>
    <converters:HorizontalDluToPixelConverter x:Key="HorizontalConverter" />
    <converters:VerticalDluToPixelConverter x:Key="VerticalConverter" />
</Window.Resources>

<Grid.RowDefinitions>
    <RowDefinition Height="{Binding Converter={StaticResource VerticalConverter}, ConverterParameter=7}" />
    etc...
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
    <ColumnDefinition Width="{Binding Converter={StaticResource HorizontalConverter}, ConverterParameter=7}" />
    etc... etc...
</Grid.ColumnDefinitions>

Hope this helps future people as well (if it is infact helpful heh)

Smolensk answered 4/10, 2014 at 2:3 Comment(0)
R
1

Look into the Grid control - it has support for relative sizing.

Regimen answered 27/12, 2008 at 17:44 Comment(1)
Does the Grid control accept units like: width="210dlu" in addition to width="9999px" ?Cow
W
1

Here is a more detailed link I found on MSDN about Layout Metrics. WPF DIUs are defined as 1/96 of an inch and DLU to pixel conversions are font dependent as you can see in the table shown below.

Converting from DLUs to relative pixels and back

So using this information along with a systems DPI setting and depending on the font that you are targeting you could figure out how many DUI correlate to a given measurement in vertical or horizontal DLU units. I haven't seen any javascript based calculators for this yet but it would be pretty trivial to create a similar tool in any programming language that makes this a little easier.

Wiskind answered 22/5, 2010 at 14:21 Comment(1)
i don't think it's trivial; no one's been able to do it yet.Cow
M
0

The Canvas layout element allows for coordinate-based layout similar to what you're used to and if you have a Canvas you even get some guidelines in the visual editor. eg:

<Window xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' xmlns:d='http://schemas.microsoft.com/expression/blend/2008' mc:Ignorable='d' Title='Spin-Echo Image Processing' Width='673' x:Class='ImageR2.CLASPmap' Height='961' xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
    <Canvas Name='canvas1'>
        <TextBlock Name='TEXT_Program' Canvas.Top='27' Width='133' Height='21' Canvas.Left='875'>CLASPmap:</TextBlock>
        <TextBlock Name='TEXT_Heading' Canvas.Top='27' Width='368' Height='27' Canvas.Left='1008'>Transverse Relaxation Rate Mapping</TextBlock>
        <TextBlock Name='TEXT_XYCoordinates' Canvas.Top='251' Width='139' Height='21' Canvas.Left='869'>X &amp; Y Coordinates</TextBlock>
Myrtlemyrvyn answered 27/5, 2009 at 19:16 Comment(1)
Problem is the values you are entering are assumed to be pixels by WPF. Where the screenshot is providing values in horizontal and vertical dialog units (DLUs). And to clarify, DLUs are not necessarily square.Cow

© 2022 - 2024 — McMap. All rights reserved.