Windows 商店应用布局不一致。

6

我正在使用Viewbox来缩放一个固定尺寸的画布(其中包含一些路径,这些路径共同形成了一幅有意义的图片)。

<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>

当本机渲染时,此XAML如上图所示,而在模拟器上渲染时则如下图所示。由于模拟器正在产生期望的结果,因此有人可以解释一下为什么第二个路径会延伸到红色面板之外?

1
我复制粘贴了你的XAML代码,看起来像下面两张图片,它应该像上面的图片一样吗? - sa_ddam213
你是否将我的XAML粘贴到Windows应用商店项目的页面中?当我在本地机器上运行XAML时,我得到了顶部的图像,而在模拟器上则是底部的图像。 - Chris Kerekes
1
这可能是由于自动缩放引起的。记录您的主监视器和模拟器的屏幕尺寸。并尝试更改您的主监视器分辨率,以查看其是否有影响。 - Hans Passant
@HansPassant 当我的本地PC(Surface Pro)使用1680x1050和1024x768分辨率时,我得到了预期的结果(即两个方块与stackpanel具有相同的宽度),但在1920x1080时却不是这样。模拟器总是能够产生正确的结果。 - Chris Kerekes
是的,1920x1080是自动缩放的起点。这很可能是代码中隐藏的四舍五入错误,你无法找到它。当然,这很难修复,你只能向微软支持寻求帮助。 - Hans Passant
2个回答

5
实际上并没有差异...发生的事情是你正在处理一个非常小的东西(你的路径非常小):screenshot。然后将其放大到极大并告诉布局使用UseLayoutRounding来四舍五入到最近的整个像素。
结果不可靠的原因是,Path是独立于Canvas缩放的,因为它实际上并没有布局其内容。因此,当您的某个路径点落在不均匀的像素边界上时(这可能会发生在某些屏幕分辨率上而在其他分辨率上则不会),它会四舍五入到未缩放画布内的最近虚拟像素,并且这是从Viewbox进行缩放,然后再次四舍五入到最近的整个像素(使用与Canvas缩放相同的比例)。这加剧了四舍五入误差。如果我们关闭StackPanel.Background(默认为透明),将Canvas.Background设置为绿色,并降低描边颜色的不透明度,则可以更容易地看到此现象: screenshot
因此,您要么必须关闭UseLayoutRounding,以便在操作中保留小数点,要么简化布局,以避免出现错误。例如,如果您通过删除不适当和多余的固定大小画布并设置Path.Stretch = Uniform来让路径自己缩放,则最终结果如下:
    <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>

导致: 屏幕截图

可能是您实际正在寻找的内容

但是,如果这只是一种过度简化,而您实际上有多条路径要放在您的Canvas中,我建议您使用一个可以自行布局的容器,最明显的选择是Grid,这样您仍然可以使路径与Grid一起自动缩放,让它们保持同步(Canvas不会对其子项进行布局)。代码如下:

    <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>

结果与没有辅助容器的结果相同

希望这能帮到你 -ck


1

我在我的机器上使用分辨率为2560x1440的模拟器并使用以下画布可以重现这个问题。

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

对于上面的片段-画布溢出/超出了红色面板。
<Canvas Width="6" Height="6">
    <Rectangle Width="6" Height="6" Fill="Blue" ></Rectangle>
</Canvas>

对于上面的代码片段 - 画布在红色面板下溢出/不适合,并在红色面板的右边缘留下一些空间。
如果保持画布大小为5的倍数,则可以正确适应红色面板。
这似乎与路径无关,因为它也可以通过矩形来重现。这似乎是ViewBox缩放的问题。我发现,在堆栈面板上使用UseLayoutRounding="False"时,问题不会再现。当寻找ViewBox缩放问题时,我还发现了一个相关线程。它建议使用SnapsToDevicePixels属性,但该属性在Windows Store XAML应用程序中不可用。
总之,尽管我不是具有ViewBox缩放算法内部知识的专业人士,但它似乎是ViewBox缩放的问题。可能的解决方法是将UseLayoutRounding设置为false,如果在另一台机器上通过测试,则可以采用此解决方法。 5的倍数看起来不是很好的解决方法,但您可以检查。另外,如果您只是想好奇为什么会发生这种情况,您可以得到答案,也许几个像素的下溢/溢出可能对您的应用程序并没有太大影响。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接