WPF、XAML 百分比间距计算全错

WPF, XMAL percentage spacing gets calculated all wrong

简而言之

我的理解是,通过使用 xaml 中的 * 您应该得到“固定”百分比。但是,即使将两个网格添加到具有完全相同的行和列定义的控件中,计算结果似乎也不同。

tl;博士

我想做什么

我想创建一个带有 canvas 或按钮的用户控件来打开颜色选择器。在设计该控件时,我偶然发现了一个我自己无法解释的问题。

控件的左侧应该几乎是右侧的完整镜像副本,只有一点点不同:最外面的线条在外观上应该略有不同。虽然左边的行应该很短,但右边的行应该放在控件的最底部以封装文本块。

我的做法

为了实现这一点,我创建了一个“主”网格来承载三个元素(左手设计网格、用于打开颜色选择器的中心控件和右手网格)。我添加了由网格封装的中心控件,只是为了与我的左右手侧方法保持一致。

继续,我为提到的左侧和右侧添加了两个网格,并为它们提供了完全相同的行和列定义。认为这样可以解决问题,我添加了几行以将希望的设计添加到控件中。

问题

我很快就注意到,两条水平线并不匹配。线条之间有几个像素,所以我尝试调整布局以找出导致该问题的原因。

'solution'

似乎一切似乎都表现正确,除了最右边的那条线。每当它的 Grid.RowSpan 设置为 4 时,这意味着它会延伸到控件的底部,它会弄乱百分比的间距。出于某种原因,我无法理解它似乎改变了 Grid.RowDefinitions

计算的百分比

只需将最右侧行的 Grid.ColumnSpan="4" 设置为 Grid.ColumnSpan="3" 即可修复间距,将最外侧行的 Grid.ColumnSpan="4" 更改为 Grid.ColumnSpan="3" 也可以正确更改间距。

新问题

此尝试显然修复了间距,但确实引入了一个新问题:使用这两个修复程序之一的用户控件的设计发生了变化。要么两条线都必须放到控件的最底部,要么两条线都必须很短。

而且我真的希望这两行略有不同。此外,中心的两条垂直线似乎根本不会对间距产生负面影响,即使它们也跨越所讨论的行。

另一种解决方案?

我只是继续将所有行更改为 canvas 具有黑色背景颜色。这确实解决了问题,一切都正确呈现。但是我却坐在这里,不明白为什么会出现这个问题。 我想了解可能导致百分比计算发生变化的原因,以提高我在使用 XAML 设计 UI 方面的知识。

然而,控件预览现在似乎可以工作,但是当被另一个控件“使用”时(意味着我已经将该控件添加到另一个控件),整个间距似乎又错了,就像以前一样当我使用线条时。

新罪魁祸首

在玩游戏时我注意到删除文本框时间距会再次正确,即使被另一个控件使用也是如此。尽管如此,我这里的问题是理解这怎么可能是一个问题,即使百分比应该都是相同的,水平线没有差异的余地。

自然而然地,我想知道负边距是否会导致错误(这是为了让 TextBlock 靠近直线)。但是不管有没有边距,错误仍然存​​在。

一个更笼统的问题

我知道,这里不太欢迎关于最佳方法和实践的一般性问题,但请让我至少询问有关如何使用 XAML 设计编写良好的控件的资源。过去几周我读到的所有内容对我帮助很大,但我似乎经常遇到很多问题。

我无法告诉您我是在 Microsoft 文档站点上的什么地方读到的,但它明确指出应该尽量避免使用 canvases。也许我误解了,但是,在我看来,在这里使用 canvas 似乎是避免我遇到的简单问题的廉价技巧。

此外,如果有人对如何更改控件布局以获得所需的输出有任何想法,请告诉我。预先感谢您花时间阅读本文。

资源

用户控制线

问题:显示的水平线略有偏差

<UserControl ...
             mc:Ignorable="d" d:DesignHeight="50"  d:DesignWidth="400"
             MinHeight="50">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="54"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <!-- left hand side grid-->
        <Grid Grid.Column="0"
              Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="1"/>
            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="2*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="1"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="2*"/>
            </Grid.RowDefinitions>

            <Line Grid.Column="0" Grid.ColumnSpan="1"
                  Grid.Row="1" Grid.RowSpan="3"
                  X1="0" X2="0"
                  Y1="0" Y2="1"
                  Stroke="Black"
                  StrokeThickness="1"
                  Stretch="Uniform"
                  SnapsToDevicePixels="True"/>
            <Line Grid.Column="0" Grid.ColumnSpan="3"
                  Grid.Row="2" Grid.RowSpan="1"
                  X1="0" X2="1"
                  Y1="0" Y2="0"
                  Stroke="Black"
                  StrokeThickness="1"
                  Stretch="Uniform"
                  SnapsToDevicePixels="True"/>
            <Line Grid.Column="2" Grid.ColumnSpan="1"
                  Grid.Row="0" Grid.RowSpan="5"
                  X1="0" X2="0"
                  Y1="0" Y2="1"
                  Stroke="Black"
                  StrokeThickness="1"
                  Stretch="Uniform"
                  SnapsToDevicePixels="True"/>
        </Grid>

        <!-- middle grid -->
        <Grid Grid.Column="1"
              Grid.Row="0">
            <Canvas Margin="2, 0"
                    Background="Red"/>
        </Grid>

        <!-- right hand side grid-->
        <Grid Grid.Column="2"
              Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="1"/>
            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="2*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="1"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="2*"/>
            </Grid.RowDefinitions>

            <Line Grid.Column="0" Grid.ColumnSpan="1"
                  Grid.Row="0" Grid.RowSpan="5"
                  X1="0" X2="0"
                  Y1="0" Y2="1"
                  Stroke="Black"
                  StrokeThickness="1"
                  Stretch="Uniform"
                  SnapsToDevicePixels="True"/>
            <Line Grid.Column="0" Grid.ColumnSpan="3"
                  Grid.Row="2" Grid.RowSpan="1"
                  X1="0" X2="1"
                  Y1="0" Y2="0"
                  Stroke="Black"
                  StrokeThickness="1"
                  Stretch="Uniform"
                  SnapsToDevicePixels="True"/>
            <Line Grid.Column="2" Grid.ColumnSpan="1"
                  Grid.Row="1" Grid.RowSpan="4"
                  X1="0" X2="0"
                  Y1="0" Y2="1"
                  Stroke="Black"
                  StrokeThickness="1"
                  Stretch="Uniform"
                  SnapsToDevicePixels="True"/>

            <TextBlock Grid.Column="1"
                       Grid.Row="3" Grid.RowSpan="2"
                       Text="Prefered Color"
                       FontSize="20"
                       FontFamily="Segoe UI Light"
                       Typography.Capitals="SmallCaps"
                       Foreground="Black"
                       HorizontalAlignment="Right"
                       Margin="4, -3, 4, 0"/>
        </Grid>
    </Grid>
</UserControl>

User-control as displayed in designer with horizontal lines being off

使用画布进行用户控制

问题:在预览中似乎有效,但添加到另一个控件时会计算错误

<UserControl ...
             mc:Ignorable="d" d:DesignHeight="50"  d:DesignWidth="400"
             MinHeight="50">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="54"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <!-- left hand side grid-->
        <Grid Grid.Column="0"
              Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="1"/>
            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="2*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="1"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="2*"/>
            </Grid.RowDefinitions>

            <Canvas Grid.Column="0" Grid.ColumnSpan="1"
                  Grid.Row="1" Grid.RowSpan="3"
                  Background="Black"
                  SnapsToDevicePixels="True"/>
            <Canvas Grid.Column="0" Grid.ColumnSpan="3"
                  Grid.Row="2" Grid.RowSpan="1"
                  Background="Black"
                  SnapsToDevicePixels="True"/>
            <Canvas Grid.Column="2" Grid.ColumnSpan="1"
                  Grid.Row="0" Grid.RowSpan="5"
                  Background="Black"
                  SnapsToDevicePixels="True"/>
        </Grid>

        <!-- middle grid -->
        <Grid Grid.Column="1"
              Grid.Row="0">
            <Canvas Margin="2, 0"
                    Background="Red"/>
        </Grid>

        <!-- right hand side grid-->
        <Grid Grid.Column="2"
              Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="1"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="1"/>
            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>
                <RowDefinition Height="2*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="1"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="2*"/>
            </Grid.RowDefinitions>

            <Canvas Grid.Column="0" Grid.ColumnSpan="1"
                  Grid.Row="0" Grid.RowSpan="5"
                  Background="Black"
                  SnapsToDevicePixels="True"/>
            <Canvas Grid.Column="0" Grid.ColumnSpan="3"
                  Grid.Row="2" Grid.RowSpan="1"
                  Background="Black"
                  SnapsToDevicePixels="True"/>
            <Canvas Grid.Column="2" Grid.ColumnSpan="1"
                  Grid.Row="1" Grid.RowSpan="4"
                  Background="Black"
                  SnapsToDevicePixels="True"/>

            <TextBlock Grid.Column="1"
                       Grid.Row="3" Grid.RowSpan="2"
                       Text="Prefered Color"
                       FontSize="20"
                       FontFamily="Segoe UI Light"
                       Typography.Capitals="SmallCaps"
                       Foreground="Black"
                       HorizontalAlignment="Right"
                       Margin="4, 0, 4, 0"/>
        </Grid>
    </Grid>
</UserControl>

User-control with canvases instead of lines being displayed correctly in designer

User-control displayed wrong after being added to another control

我将post这个作为答案,因为它满足了必要的设计需求,暂时将其标记为正确答案。 但是,这个答案并没有完全回答我的问题,因为它没有解释为什么以前的方法不起作用。

因此,请随时添加答案,我会选择能够解释问题的答案作为正确答案。

<UserControl ...
             mc:Ignorable="d" d:DesignHeight="50"  d:DesignWidth="400"
             MinHeight="50">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="1"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="10"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="1"/>
            <ColumnDefinition Width="40"/>
            <ColumnDefinition Width="1"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="1"/>
        </Grid.ColumnDefinitions>

        <Button Grid.Column="3"
                Grid.Row="0" Grid.RowSpan="5"
                Margin="4,0"
                Background="Red"
                BorderThickness="0"
                Command="{Binding ColorClick}">
        </Button>

        <TextBlock Grid.Column="5"
                   Grid.Row="4" Grid.RowSpan="2"
                   Text="Prefered Color"
                   FontSize="20"
                   FontFamily="Segoe UI Light"
                   Typography.Capitals="SmallCaps"
                   Foreground="Black"
                   HorizontalAlignment="Right"
                   Margin="4, 0, 4, 0"/>

        <Canvas Grid.Column="0"
                Grid.Row="1" Grid.RowSpan="3"
                Background="Black"/>
        <Canvas Grid.Column="1"
                Grid.Row="2" Grid.RowSpan="1"
                Background="Black"/>
        <Canvas Grid.Column="2"
                Grid.Row="0" Grid.RowSpan="5"
                Background="Black"/>
        <Canvas Grid.Column="4"
                Grid.Row="0" Grid.RowSpan="5"
                Background="Black"/>
        <Canvas Grid.Column="5"
                Grid.Row="2" Grid.RowSpan="1"
                Background="Black"/>
        <Canvas Grid.Column="6"
                Grid.Row="1" Grid.RowSpan="5"
                Background="Black"/>

    </Grid>
</UserControl>