Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows Store App Layout Discrepencies

I'm using a Viewbox to scale a fixed size canvas (containing various paths that together form a meaningful picture).

<StackPanel Background="Red" Width="400" UseLayoutRounding="True">
    <StackPanel.Resources>
        <Style TargetType="Viewbox">
            <Setter Property="Height" Value="400" />
            <Setter Property="Margin" Value="0,0,0,50" />
        </Style>
        <Style TargetType="Path">
            <Setter Property="Stroke" Value="Blue" />
            <Setter Property="StrokeThickness" Value="2" />
        </Style>
    </StackPanel.Resources>
    <Viewbox>
        <Canvas Width="5" Height="5">
            <Path Data="M 1,1 h 3 v 3 h -3 z" />
        </Canvas>
    </Viewbox>
    <Viewbox>
        <Canvas Width="6" Height="6">
            <Path Data="M 1,1 h 4 v 4 h -4 z" />
        </Canvas>
    </Viewbox>
</StackPanel>

This xaml appears as shown on top when rendered natively on my PC and as shown on the bottom when rendered on an emulator. As the emulator is producing the desired result can someone please explain to me why the second path extends beyond the red panel?

rendered natively on my PCrendered on an emulator

like image 702
Chris Kerekes Avatar asked Mar 14 '13 20:03

Chris Kerekes


People also ask

Why Windows Store has less apps?

That's because Microsoft's new application platform is designed to be more limited. Apps are run in a sandbox, limiting the files they can access on your system.


2 Answers

There really isn't a discrepancy... what's happening is that you are taking something that renders really small (your path is very small):

screenshot

look at the tiny boxes

...and scaling it up extremely large and telling the layout to round to the nearest whole pixel via UseLayoutRounding

the reason why the result is unreliable is that the Paths are being scaled independently of the Canvas since it doesn't actually layout its contents. So when one of your path points land on an uneven pixel boundary (which could happen at some screen resolutions and not others) it's rounding to the nearest virtual pixel inside the un-scaled the canvas and this is getting scaled from the Viewbox and then rounded again to the nearest whole pixel (using the same scale the Viewbox determined by the scaling of the Canvas) exacerbating the rounding error. You can see this illustrated more easily if we turn off the StackPanel.Background (default is transparent) set the Canvas.Background to green and dial down the opacity on the color of the stroke:

screenshot

you can see the path rounding is different than the canvas

So you either have to turn off UseLayoutRounding so that there is decimal points carried through the operation or simplify your layout so that the errors don't occur.

For instance, if you let the paths scale themselves by removing the inappropriate and superfluous fixed size canvas and setting Path.Stretch = Uniform you end up with:

    <StackPanel Background="Red" Width="400" UseLayoutRounding="True">
        <StackPanel.Resources>
            <Style TargetType="Viewbox">
                <Setter Property="Height" Value="400" />
                <Setter Property="Margin" Value="0,0,0,50" />
            </Style>
            <Style TargetType="Path">
                <Setter Property="Stroke" Value="Blue" />
                <Setter Property="StrokeThickness" Value="2" />
                <Setter Property="Stretch" Value="Uniform" />
            </Style>
        </StackPanel.Resources>
        <Viewbox>
            <Path Data="M 1,1 h 3 v 3 h -3 z" />
        </Viewbox>
        <Viewbox>
            <Path Data="M 1,1 h 4 v 4 h -4 z" />
        </Viewbox>
    </StackPanel>

resulting in: screenshot

probably what you were actually looking for

However if this was an over simplification and you actually have multiple paths that you intended to put inside your Canvas, I suggest you use a container that actually does its own layout, the obvious choice is a Grid this way you can still have the paths scale themselves along with the Grid keeping them in lock-step (Canvass won't layout their children). The code would look like:

    <StackPanel Background="Red" Width="400" UseLayoutRounding="True">
        <StackPanel.Resources>
            <Style TargetType="Viewbox">
                <Setter Property="Height" Value="400" />
                <Setter Property="Margin" Value="0,0,0,50" />
            </Style>
            <Style TargetType="Path">
                <Setter Property="Stroke" Value="Blue" />
                <Setter Property="StrokeThickness" Value="2" />
                <Setter Property="Stretch" Value="Uniform" />
            </Style>
        </StackPanel.Resources>
        <Viewbox>
            <Grid Width="5" Height="5">
                <Path Data="M 1,1 h 3 v 3 h -3 z" />
            </Grid>
        </Viewbox>
        <Viewbox>
            <Grid Width="6" Height="6">
                <Path Data="M 1,1 h 4 v 4 h -4 z" />
            </Grid>
        </Viewbox>
    </StackPanel>

and the result is identical to the one without a secondary container

hope this helps -ck

like image 108
ckozl Avatar answered Sep 20 '22 08:09

ckozl


I could reproduce the problem on my machine with emulator at display resolution of 2560x1440 with canvas as below.

<Canvas Width="4" Height="4">
    <Rectangle Width="4" Height="4" Fill="Blue" ></Rectangle>
</Canvas>

For above snippet - canvas overflows/goes-beyond the red panel.

<Canvas Width="6" Height="6">
    <Rectangle Width="6" Height="6" Fill="Blue" ></Rectangle>
</Canvas>

For above snippet - canvas underflows/does-not-fit the red panel, and leaves some space on right margin of the red panel.

if the canvas size is kept multiple of 5, it fits properly in red panel.

It does not seem to be an issue with Path since it reproduces with rect also. It seem to be issue with ViewBox scaling. I found that with UseLayoutRounding="False" on stackpanel - issues does not reproduce. I also found a related thread when looking around for ViewBox scaling issues. It suggest to use SnapsToDevicePixels property but that is not available for windows store xaml apps.

In summary, it seem to be an issues with ViewBox scaling though I am not a pro with internal knowledge of viewbox scaling algo. Possible workaround is to set UseLayoutRounding to false if it passes the test on another machine. The multiple of 5 does not look like as good workaround but you can check. On a separate note - if you were just curious to know why it is happening, you get the answer and may be underflow/overflow of few pixels may out matter for your application.

like image 28
Sushil Avatar answered Sep 21 '22 08:09

Sushil