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

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 Path
s 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:

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:

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 (Canvas
s 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