XAML元素填充所有剩余空间。

4

我有一个WPF应用程序,正在尝试正确定位元素。只有四个元素,所以应该很简单,但我就是无法使其正常工作。

其中一个棘手的问题是当窗口出现时,它会自行调整大小到(大约)桌面窗口的大小,因此它没有固定的大小。

这些元素应该从上到下堆叠,所以Stack Panel似乎很自然。但是第三个元素必须占据前两个和最后一个元素未占据空间的所有剩余空间。无论我尝试什么,它都会占用太多或太少的空间。唯一看起来能工作的方法是给它一个具体的像素大小,但正如上面所述,这不起作用。

我最近尝试的是Dock Panel。虽然在Visual Studio设计器中看起来正确,但执行时,第三个元素-Canvas-完全覆盖了底部元素。

我的XAML:

<DockPanel>
    <Button x:Name="btnClose" DockPanel.Dock="Top" Content="X" 
            HorizontalAlignment="Right" Margin="0,5,5,0" VerticalAlignment="Top" 
            Width="Auto" Height="Auto" Background="Black" 
            Foreground="White" Click="btnClose_Click"/>
    <Label x:Name="lblTitle" DockPanel.Dock="Top" Content="My Title" 
           HorizontalAlignment="Center" VerticalAlignment="Top" Width="Auto" 
           Foreground="White" FontWeight="Bold" FontSize="22"/>

    <Label x:Name="lblControls" DockPanel.Dock="Bottom" Content="Placeholder" 
           HorizontalAlignment="Center" VerticalAlignment="Bottom" Width="Auto" 
           Height="Auto" Foreground="White" FontWeight="Bold" FontSize="22"/>

    <Border x:Name="CanvasBorder" BorderBrush="White" BorderThickness="5" >
        <Canvas x:Name="cvsChart" Grid.Row="0" HorizontalAlignment="Stretch"
                VerticalAlignment="Top" Width="Auto">
        </Canvas>
    </Border>
</DockPanel>

有没有办法让该画布延伸并填充其他三个不占用的空间?

更新 由于@Peter Duniho向我证明了代码的有效性,我尝试了一个实验并删除了窗口出现时我已经放置的调整大小代码。将其删除后,窗口会绝对正确地显示。这是我将其调整为(大多数情况下)桌面大小的方法:

public const int WINDOW_OFFSET = 10;
...

int screenWidth = (int)System.Windows.SystemParameters.PrimaryScreenWidth;
int screenHeight = (int)System.Windows.SystemParameters.PrimaryScreenHeight;

// center this window in desktop
Width = screenWidth - WINDOW_OFFSET;
Height = screenHeight - WINDOW_OFFSET;
Left = WINDOW_OFFSET/2;
Top = WINDOW_OFFSET/2;

我进行了一些搜索,发现在“Stack Overflow”上有一个评论建议获取WorkArea而不是PrimaryScreenHeight。我尝试了一下,哇! 整个应用程序窗口都出现了。

int screenWidth = (int)System.Windows.SystemParameters.WorkArea.Width;
int screenHeight = (int)System.Windows.SystemParameters.WorkArea.Height;

事实证明,底部行已经被显示了,只是因为它出现在屏幕的底部以下,所以我看不到。现在我能看到它了,回到了开发天堂!感谢大家的帮助!
2个回答

8

有几种可能的方法可以实现这个目标。其中最简单的一种是将您的元素放在一个 Grid 中,并将除第三行之外的所有行高设置为 Auto

  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
      <RowDefinition/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Button x:Name="btnClose" Content="X" Grid.Row="0"
            HorizontalAlignment="Right" Margin="0,5,5,0" VerticalAlignment="Top" 
            Width="Auto" Height="Auto" Background="Black" 
            Foreground="White" Click="btnClose_Click"/>
    <Label x:Name="lblTitle" Content="My Title" Grid.Row="1"
           HorizontalAlignment="Center" VerticalAlignment="Top" Width="Auto" 
           Foreground="White" FontWeight="Bold" FontSize="22"/>

    <Label x:Name="lblControls" Content="Placeholder" Grid.Row="3"
           HorizontalAlignment="Center" VerticalAlignment="Bottom" Width="Auto" 
           Height="Auto" Foreground="White" FontWeight="Bold" FontSize="22"/>

    <Border x:Name="CanvasBorder" BorderBrush="White" BorderThickness="5" Grid.Row="2">
      <Canvas x:Name="cvsChart" Grid.Row="0" HorizontalAlignment="Stretch"
                VerticalAlignment="Top" Width="Auto">
      </Canvas>
    </Border>
  </Grid>

网格行定义高度的默认设置为"*",这意味着将所有剩余的空间分配给使用该设置的所有行。只有一个行使用此设置时,它将获得所有剩余的空间。

这会产生一个看起来像这样的窗口:

four row grid with border and canvas filling the third row

(我将窗口背景设置为Gray,这样您的白色文本和边框就会显示出来。)

实际上,另一个选项是使用DockPanel。在我看来,您尝试中的主要问题是将lblControls元素设置为DockPanel.Dock="Bottom",而应该改为Top。当我将其更改为Top时,它似乎对我有效。

根据您下面的评论,似乎您实际上确实希望将lblControls设置为DockPanel.Dock="Bottom",并且实际上您发布的代码似乎也可以实现您想要的效果。对于我来说,不清楚您的代码与您想要的有何不同。如果您提供一个可靠地重现问题的良好最小完整和可验证代码示例,那将更好。


谢谢回复,但两种方法都没有起作用。Border和Canvas应该出现在窗口的中间。据我所知,最后添加并不给它一个停靠位置就应该做到这一点。当我将lblControls设置为顶部时,它们出现在顶部,位于Border和Canvas的上方,因为它们被告知要这样做,而不是它们应该这样做。Grid的方法也不起作用。我将所有行的高度都设为“自动”,除了Border和Canvas,它们的高度为“*”。它也隐藏了底部的标签。 - Frecklefoot
1
@Frecklefoot:「边框和画布应该出现在窗口中间」——抱歉,您的问题并没有明确所需的结果。您发布的代码确实做到了这一点,将 lblControls 放置在底部,而 CanvasBorder 与其中的 cvsChartlblTitlelblControls 之间。我可以编辑 Grid 示例以符合您的评论,但最终不清楚为什么您在问题中提供的代码不能达到您想要的效果。根据您在此处的评论,它似乎已经做到了。 - Peter Duniho
抱歉我的原始问题表述不够清晰。我担心这可能是个问题,因为我把边框和画布放在最后面。那么我一定是做错了其他事情,因为我仍然发现底部标签被边框和画布完全覆盖。至少我认为是这样,因为当我运行它时根本看不到它。但是我的应用程序除了出现之外还没有做任何事情。 - Frecklefoot
我刚刚取消了窗口大小调整的出现,它确实起作用了。因此,窗口大小调整一定会在某种程度上搞砸它。这就是我的问题所在。感谢您的所有帮助。我将把您的输入标记为答案,因为它促使我真正找出问题所在... - Frecklefoot
1
@Freckle:好的,很高兴能够提供一些帮助。请记住,画布的内容不会被裁剪到画布中。也就是说,画布可以根据网格或停靠面板进行布局,但如果画布内部有比该布局更大的东西,它将覆盖在画布下方布局的任何内容。如果您需要调整大小行为的帮助,请发布一个新问题,并提供一个可靠重现问题的良好 [mcve],以及对代码执行和所需执行的操作的精确说明。考虑使用截图来显示这些细节。 - Peter Duniho

2

去除画布的垂直对齐


谢谢,但那没有任何区别。 - Frecklefoot

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