gpt4 book ai didi

c# - 为什么在嵌套网格中调整星号大小不起作用?

转载 作者:可可西里 更新时间:2023-11-01 07:46:54 25 4
gpt4 key购买 nike

考虑以下 XAML:

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Content="Button" HorizontalAlignment="Left"/>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="B" Margin="5"/>
<Button Content="Button" Grid.Column="1" Margin="5"/>
</Grid>
</Grid>

以上,所有 ColumnDefinition除一个之外的值使用 Width 的默认值, 即 "*" ,即“星级”。一个异常(exception)是包含嵌套 Grid 的列。控件,设置为 "Auto" .

我希望它的工作方式如下:
  • Grid根据其内容的需要调整第二列的大小,然后将控件的剩余宽度分配给第一列。
  • 内部Grid将其可用空间平均分配给两列。毕竟,它们都设置为使用star sizing,而star sizing 应该设置GridLength属性(宽度,在这种情况下)到可用空间的加权分布。此内部的最小布局大小 Grid (外部 Grid 需要计算其第二列的宽度)是均匀分布宽度的星形列的总和(即在这种情况下,是内容最宽的列宽度的两倍)。

  • 但是,嵌套网格的列宽是根据计算出的每个按钮的最小尺寸设置的,两个星形列之间没有明显的加权关系(为了清晰起见,显示了网格线):

    incorrectly distributed column widths

    如果我没有外部网格,它会按预期工作,即只是让内部网格成为窗口中唯一的网格:

    correctly distributed column widths

    两列被强制大小相同,然后当然左手按钮被拉伸(stretch)以适应其包含单元格的大小(这是我想要的......最终目标是让这两个按钮具有相同的宽度,网格列提供了实现这一点的布局)。

    在这个特定的例子中,我可以使用 UniformGrid作为一种解决方法,强制均匀分布列宽。这就是我想要它的实际外观( UniformGrid 没有 ShowGridLines 属性,所以你只需要想象两个最右边的按钮之间的假想线):

    enter image description here

    但我真的很想更广泛地了解如何实现这一点,以便在更复杂的场景中我能够在嵌套的 Grid 中使用 star-sizing。控制。

    似乎不知何故,被包含在另一个 Grid 的单元格中控件正在改变为内部 Grid 计算星号大小的方式控制(或完全防止星级调整产生任何影响)。但为什么会这样呢?我是否(又一次)错过了 WPF 的一些深奥的布局规则,将其解释为“按设计”行为?或者这只是框架中的一个错误?

    更新:

    我理解 Ben 的回答意味着在考虑了每列的最小尺寸后,star-sizing 应该只分配剩余的空间。但这不是人们在其他场景中看到的。

    例如,如果包含内部网格的列已明确调整大小,那么对内部网格的列使用星型大小会导致列的大小均匀,正如我所期望的那样。

    IE。这个 XAML:

    <Grid ShowGridLines="True">
    <Grid.ColumnDefinitions>
    <ColumnDefinition/>
    <!--
    <ColumnDefinition Width="Auto"/>
    -->
    <ColumnDefinition Width="60"/>
    </Grid.ColumnDefinitions>
    <Button Content="Button" HorizontalAlignment="Left"/>
    <Grid Grid.Column="1" ShowGridLines="True">
    <Grid.ColumnDefinitions>
    <ColumnDefinition/>
    <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Button Content="B" Margin="5"/>
    <Button Content="Button" Grid.Column="1" Margin="5"/>
    </Grid>
    </Grid>

    产生这个输出:

    enter image description here

    换句话说,在最坏的情况下,我希望 WPF 首先计算内部网格的最小尺寸而不考虑星号大小(例如,如果短按钮需要 10 像素,长按钮需要 70,那么总宽度将是80),然后仍然均匀分布列宽(即在 10/70 示例中,每列将结束为 40 像素,截断较长的按钮,类似于上图)。

    为什么star-sizing 有时会在列之间均匀分布宽度,有时则不是?

    更新 #2:

    这是一个简单的示例,它清楚而生动地展示了 WPF 如何根据是否是计算 Grid 的人来不同地处理星号大小。宽度或者你是:

    <Window x:Class="TestGridLayout2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    SizeToContent="WidthAndHeight"
    Title="MainWindow">
    <Window.Resources>
    <Style TargetType="Border">
    <Setter Property="BorderBrush" Value="Black"/>
    <Setter Property="BorderThickness" Value="1"/>
    </Style>
    <Style TargetType="TextBlock">
    <Setter Property="FontSize" Value="24"/>
    </Style>
    </Window.Resources>
    <Grid>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="3*"/>
    </Grid.ColumnDefinitions>

    <Border Grid.Column="0"/>
    <Border Grid.Column="1"/>

    <StackPanel>
    <TextBlock Text="Some text -- one"/>
    <TextBlock Text="Some text -- two"/>
    <TextBlock Text="Some text -- three"/>
    </StackPanel>
    <StackPanel Grid.Column="1">
    <TextBlock Text="one"/>
    <TextBlock Text="two"/>
    <TextBlock Text="three"/>
    </StackPanel>
    </Grid>
    </Window>

    当你运行程序时,你会看到:

    enter image description here

    WPF 已忽略星号大小,将每列宽度设置为最小值。如果您只是单击窗口边框,就像调整窗口大小一样(您甚至不必将边框实际拖动到任何地方), Grid布局被重做,你会得到这个:

    enter image description here

    此时,将应用星号大小(正如我所期望的),并且列根据 XAML 声明进行比例调整。

    最佳答案

    我同意 Ben 的回答强烈暗示了这里封面下可能发生的事情:

    正如 Ben 指出的那样,WPF 在计算内部 Grid 时忽略了星级大小。对象的最小宽度(也许合理......我认为有诚实辩论的空间,但显然这是一种可能且合法的设计)。

    不清楚(以及 Ben 没有回答)是为什么这意味着在计算该内部 Grid 内的列宽时也忽略了星号大小。 .由于在外部施加宽度时,比例宽度将导致内容在必要时被截断以保留这些比例,为什么当根据内容的最小所需大小自动计算宽度时不会发生同样的事情。

    IE。我仍在寻找我的问题的答案。

    与此同时,恕我直言,有用的答案包括解决该问题的方法。虽然不是我问题本身的实际答案,但它们显然对可能遇到问题的任何人都有帮助。所以我写这个答案是为了整合所有已知的解决方法(无论好坏,WPF 的一个重要“特性”是似乎总是至少有几种不同的方法来实现相同的结果:))。

    解决方法 #1:

    使用 UniformGrid而不是 Grid对于内部网格对象。此对象不具有与 Grid 相同的所有功能当然,不允许任何列的宽度不同。所以它可能不适用于所有场景。但它确实很容易解决这里的简单问题:

    <Grid>
    <Grid.ColumnDefinitions>
    <ColumnDefinition/>
    <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Button Content="Button" HorizontalAlignment="Left"/>
    <UniformGrid Rows="1" Columns="2" Grid.Column="1">
    <Button Content="B" Margin="5"/>
    <Button Content="Button" Grid.Column="1" Margin="5"/>
    </UniformGrid>
    </Grid>

    解决方法 #2:

    绑定(bind) MinWidth较小内容对象的属性(例如,这里是网格中的第一个 Button)到 ActualWidth较大者的属性(property)。
    这当然需要知道哪个对象的宽度最大。在本地化方案中,这可能会出现问题,因为除了文本资源之外,还必须对 XAML 进行本地化。但无论如何这有时是必要的,所以...... :)

    这看起来像这样(基本上是回答者 dub stylee 提供的 an answer here ):

    <Grid>
    <Grid.ColumnDefinitions>
    <ColumnDefinition/>
    <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Button Content="Button" HorizontalAlignment="Left"/>
    <Grid Grid.Column="1">
    <Grid.ColumnDefinitions>
    <ColumnDefinition/>
    <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <Button Content="B" Margin="5"
    MinWidth="{Binding ElementName=button2, Path=ActualWidth}"/>
    <Button x:Name="button2" Content="Button" Grid.Column="1" Margin="5"/>
    </Grid>
    </Grid>

    一个变体(为简洁起见,我不会在这里包括)将使用 MultiBinding它将所有相关控件作为输入并返回最大的 MinWidth的集合。当然,此绑定(bind)将用于 Width每个 ColumnDefinition ,以便所有列都显式设置为最大的 MinWidth .

    绑定(bind)方案还有其他变化,具体取决于您要使用和/或设置的宽度。这些都不是理想的,不仅因为潜在的本地化问题,还因为它在 XAML 中嵌入了更明确的关系。但在很多场景下,它都能完美运行。

    解决方法 #3:

    通过使用 SharedSizeGroup ColumnDefinition 的属性(property)值,可以明确强制一组列具有相同的宽度。在这种方法中,内部 Grid然后在此基础上计算对象的最小宽度,当然宽度也相同。

    例如:

    <Grid>
    <Grid.ColumnDefinitions>
    <ColumnDefinition/>
    <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Button Content="Button" HorizontalAlignment="Left"/>
    <Grid Grid.Column="1" IsSharedSizeScope="True">
    <Grid.ColumnDefinitions>
    <ColumnDefinition SharedSizeGroup="buttonWidthGroup"/>
    <ColumnDefinition SharedSizeGroup="buttonWidthGroup"/>
    </Grid.ColumnDefinitions>
    <Button Content="B" Margin="5"/>
    <Button Content="Button" Grid.Column="1" Margin="5"/>
    </Grid>
    </Grid>

    这种方法允许使用 Grid ,从而获得该对象的所有正常特征,同时解决所关注的特定行为。我希望它不会干扰 SharedSizeGroup 的任何其他合法使用。 .

    但是,它确实意味着 "Auto"调整大小,并排除 "*" (星)尺码。在这种特殊情况下,这不是问题,但就像 UniformGrid 的情况一样。变通方法,当尝试将其与其他尺寸组合时,它确实限制了一个人的选择。例如。有第三列使用 "Auto"并想要 SharedSizeGroup列占用 Grid 的剩余空间.

    尽管如此,这在许多情况下都可以正常工作,没有任何问题。

    解决方法 #4:

    我最终重新审视了这个问题,因为我遇到了主题的变化。在这种情况下,我正在处理一种情况,我希望调整大小的列具有不同的比例。上述所有解决方法都假定列大小相等。但我希望(例如)一列拥有 25% 的空间,另一列拥有 75% 的空间。和以前一样,我想要 Grid 的总大小以适应所有列所需的最小宽度。

    这种解决方法涉及简单地明确地自己做我认为 WPF 应该做的计算。 IE。取每列内容的最小宽度,以及指定的比例大小,计算 Grid 的实际宽度控制。

    这是一个可以做到这一点的方法:
    private static double ComputeGridSizeForStarWidths(Grid grid)
    {
    double maxTargetWidth = double.MinValue, otherWidth = 0;
    double starTotal = grid.ColumnDefinitions
    .Where(d => d.Width.IsStar).Sum(d => d.Width.Value);

    foreach (ColumnDefinition definition in grid.ColumnDefinitions)
    {
    if (!definition.Width.IsStar)
    {
    otherWidth += definition.ActualWidth;
    continue;
    }

    double targetWidth = definition.ActualWidth / (definition.Width.Value / starTotal);

    if (maxTargetWidth < targetWidth)
    {
    maxTargetWidth = targetWidth;
    }
    }

    return otherWidth + maxTargetWidth;
    }

    此代码查找仍可容纳每列最小宽度和比例大小的每个星形大小的列的最小宽度,以及未使用星形大小的其余列。

    您可以在适当的时间调用此方法(例如在 Grid.Loaded 事件处理程序中),然后将其返回值分配给 Grid.Width属性强制宽度为正确的大小,以适应所有列所需的最小宽度,同时保持指定的比例。

    类似的方法会对行高做同样的事情。

    解决方法 #5:

    我想值得指出的是:可以简单地指定 Grid大小明确。这仅适用于预先知道大小的内容,但同样,在许多情况下这会很好。 (在其他情况下,它会截断内容,因为即使指定的大小太小,当它是明确的时,WPF 会继续并应用星形大小比例)。

    我鼓励其他人在这个答案中添加额外的变通方法,如果他们意识到与已经展示的那些变通方法有实质性不同的好的变通方法。或者,您可以随意在您的解决方法中发布另一个答案,我会(在我方便的时候尽早 :) )自己将其添加到此处。

    关于c# - 为什么在嵌套网格中调整星号大小不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30719453/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com