2

我使用嵌套网格在 WPF 应用程序中创建了一个较大的输入表单。我正在使用 VS2010 和 VS2012 Ultimate。

这是代码:

<Window x:Class="Gridtest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow">

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="16*"/>
        <ColumnDefinition Width="10*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <Grid Grid.Column="0" Grid.Row="0" Grid.RowSpan="2">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="136*"/>
            <ColumnDefinition Width="271*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Label Grid.Row="0" Grid.Column="0" Content="Battery Name"/>
        <Label Grid.Row="1" Grid.Column="0" Content="FDC Callsign"/>
        <Label Grid.Row="2" Grid.Column="0" Content="Battery Type"/>
        <Label Grid.Row="3" Grid.Column="0" Content="GRID"/>
        <Label Grid.Row="4" Grid.Column="0" Content="ALT"/>
        <Label Grid.Row="5" Grid.Column="0" Content="Dir. of Fire"/>
        <Label Grid.Row="6" Grid.Column="0" Content="Target Prefix"/>
        <Label Grid.Row="7" Grid.Column="0" Content="Target # Start"/>

        <Grid Grid.Column="1" Grid.ColumnSpan="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>

            <ComboBox x:Name="EBattName"  IsEditable="True" ItemsSource="{Binding BatteryList}" SelectedItem="{Binding SelectedBattery, Mode=TwoWay}" DisplayMemberPath="Name"/>
            <Button x:Name="EBattSave" Grid.Column="1" Content="Add"/>
        </Grid>
        <TextBox x:Name="EBattCallsign" Grid.Row="1" Grid.Column="1" DataContext="{Binding SelectedBattery}" Text="{Binding Callsign}" Grid.ColumnSpan="2"/>
        <ComboBox x:Name="EBattType" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" DataContext="{Binding SelectedBattery}" SelectedItem="{Binding BWeapon}" DisplayMemberPath="Designation"/>
        <TextBox x:Name="EBattGrid" Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" DataContext="{Binding SelectedBattery}" Text="{Binding Coords.Grid}"/>
        <TextBox x:Name="EBattAlt" Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2" DataContext="{Binding SelectedBattery}" Text="{Binding Coords.Altitude}"/>
        <TextBox x:Name="EBattDir" Grid.Row="5" Grid.Column="1" Grid.ColumnSpan="2" DataContext="{Binding SelectedBattery}" Text="{Binding Dir}"/>
        <TextBox x:Name="EBattPre" Grid.Row="6" Grid.Column="1" Grid.ColumnSpan="2" DataContext="{Binding SelectedBattery}" Text="{Binding Prefix}"/>
        <TextBox x:Name="EBattStart" Grid.Row="7" Grid.Column="1" Grid.ColumnSpan="2" DataContext="{Binding SelectedBattery}" Text="{Binding Start}"/>
    </Grid>

    <Grid Grid.Column="0" Grid.Row="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Label Grid.ColumnSpan="3" Content="NEW MISSION"/>

        <Button x:Name="BMissionGrid" Grid.Row="1" Content="GRID"/>
        <Button x:Name="BMissionPolar" Grid.Column="1"  Grid.Row="1" Content="POLAR"/>
        <Button x:Name="BMissionShift" Grid.Column="2"  Grid.Row="1" Content="SHIFT"/>
    </Grid>

    <!-- Adding negative bottom margin to this grid helps... -->
    <Grid Grid.Column="1" Grid.Row="0" Grid.RowSpan="3" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Label Grid.Row="0" Grid.ColumnSpan="2" Content="OBSERVER INFORMATION"/>

        <Label Grid.Row="1" Grid.Column="0" Content="Select"/>
        <Label Grid.Row="2" Grid.Column="0" Content="Name"/>
        <Label Grid.Row="3" Grid.Column="0" Content="Grid"/>
        <Label Grid.Row="4" Grid.Column="0" Content="Alt"/>


        <Grid  Grid.Row="1" Grid.Column="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <ComboBox Grid.Column="0" x:Name="EObsSelect" ItemsSource="{Binding SelectedBattery.Observers}" SelectedItem="{Binding SelectedObserver, Mode=TwoWay}" DisplayMemberPath="Name" />
            <Button Grid.Column="1" x:Name="BObserverAdd" Content="New"/>
        </Grid>

        <TextBox x:Name="EObsName" Grid.Row="2" Grid.Column="1" Text="{Binding SelectedObserver.Name}"          />
        <TextBox x:Name="EObsGrid" Grid.Row="3" Grid.Column="1" Text="{Binding SelectedObserver.Coord.Grid}"    />
        <TextBox x:Name="EObsAlt" Grid.Row="4" Grid.Column="1"  Text="{Binding SelectedObserver.Coord.Altitude}"/>

        <Label Grid.ColumnSpan="2" Grid.Row="5" Content="KNOWN POINTS"/>

        <Label Grid.Row="6" Grid.Column="0" Content="Select"/>
        <Label Grid.Row="7" Grid.Column="0" Content="Name"/>
        <Label Grid.Row="8" Grid.Column="0" Content="Grid"/>
        <Label Grid.Row="9" Grid.Column="0" Content="Alt"/>

        <Grid  Grid.Row="6" Grid.Column="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <ComboBox x:Name="EKPSelect" Grid.Column="0" ItemsSource="{Binding SelectedBattery.Knownpoints}" SelectedItem="{Binding SelectedPoint, Mode=TwoWay}" DisplayMemberPath="Name"/>
            <Button Grid.Column="1" x:Name="BKnownpointAdd" Content="New"/>
        </Grid>

        <TextBox x:Name="EKPName" Grid.Row="7" Grid.Column="1"  Text="{Binding SelectedItem.Name, ElementName=EKPSelect}"          />
        <TextBox x:Name="EKPGrid" Grid.Row="8" Grid.Column="1"  Text="{Binding SelectedItem.Coord.Grid, ElementName=EKPSelect}"    />
        <TextBox x:Name="EKPAlt" Grid.Row="9" Grid.Column="1"   Text="{Binding SelectedItem.Coord.Altitude, ElementName=EKPSelect}"/>
    </Grid>


    <Grid Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label Content="MISSION LIST"/>

        <ListView Grid.Row="1" SelectionMode="Single"
            DataContext="{Binding SelectedBattery}"
            ItemsSource="{Binding Missions}"
                  >
            <ListView.View>
                <GridView>
                    <GridViewColumn DisplayMemberBinding="{Binding TargetNumber}" Header="Target No"/>
                    <GridViewColumn DisplayMemberBinding="{Binding TargetDescription}" Header="Description"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Coords.Grid}" Header="Location"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Coords.Altitude}" Header="Altitude"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Attitude}" Header="Attitude"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Length}" Header="Length"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Radius}" Header="Radius"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Notes}" Header="Remarks"/>
                </GridView>
            </ListView.View>
        </ListView>

    </Grid>

</Grid>

我从我的项目中提取了它并删除了指向我的项目命名空间的所有事件处理程序和绑定,因此您可以将其粘贴到新的 WPF 应用程序项目中并亲自查看。

这是结果窗口:

设计视图:(额外的间距用红色标记)
在此处输入图像描述 运行时视图: 在此处输入图像描述

它应该是什么样子的 ASCII 视图:

---------------
| 1 | |
--------| 3 |
| 2 | |
---------------
| 4 |
---------------

它会产生我不想要的大量垂直间距。这是从哪里来的?我该如何解决?正如我在上面的代码中所标记的,将Margin="0,0,0,-200"添加到其中一个网格会有所帮助,但这看起来很丑陋。

我可能会从头开始重建网格以减少嵌套,但在我看来,这似乎不应该发生。

编辑:我用最少的嵌套重建了网格,所以它只是一个包含所有元素的大网格:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/><!-- Left Labels -->
        <ColumnDefinition Width="10*"/><!-- Left Edit controls --> 
        <ColumnDefinition Width="Auto"/><!-- Right labels -->
        <ColumnDefinition Width="7*"/><!-- Right Edit controls -->
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" /> <!-- Everything in its own row -->
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*"    /> <!-- Listview in this row -->
    </Grid.RowDefinitions>

    <!-- Elements here -->

</Grid>

这在没有任何明显问题的情况下有效。

4

1 回答 1

1

我正在使用您的代码进行测试,并注意到一些奇怪的行为。您的面板应呈现如下:

---------------
| 1 | |
--------| 3 |
| 2 | |
---------------
| 4 |
---------------

但他们目前正在这样渲染,额外的空间被添加到 2 和 3 单元格的底部。

---------------
| 1 | |
--------| 3 |
| 2 | |
| | |
---------------
| 4 |
---------------

出于某种原因,单元格#3 中添加的元素通过在底部添加额外空间来扩展单元格高度。

奇怪的是,我发现这只发生在你的RowSpanfor cell #3 设置为奇数时。如果您将其设置为 2 或 4,它似乎渲染得很好。

<Grid>
    <Grid x:Name="1" Grid.Column="0" Grid.Row="0" ... />
    <Grid x:Name="2" Grid.Column="0" Grid.Row="1" ... />
    <Grid x:Name="3" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" ... />
    <Grid x:Name="4" Grid.Column="0" Grid.Row="3" Grod.ColumnSpan="2" ... />
</Grid>

<Grid>
    <Grid x:Name="1" Grid.Column="0" Grid.Row="0" Grid.RowSpan="3" ... />
    <Grid x:Name="2" Grid.Column="0" Grid.Row="3" ... />
    <Grid x:Name="3" Grid.Column="1" Grid.Row="0" Grid.RowSpan="4" ... />
    <Grid x:Name="4" Grid.Column="0" Grid.Row="4" Grod.ColumnSpan="2" ... />
</Grid>

删除单元格#3 中的大部分元素正确地将单元格绘制到正确的高度,减少#3 中的元素数量会缩小高度,但不会消除它,所以它可能与计算边距或填充有关?

所以我的建议是让 RowSpan=2 像第一个例子一样,或者改变你的面板布局,就像这样:

<StackPanel>
    <DockPanel>
        <Grid x:Name="3" DockPanel.Dock="Right" ... />
        <Grid x:Name="2" DockPanel.Dock="Top" ... />
        <Grid x:Name="1" ... />
    </DockPanel>
    <Grid x:Name="4" ... />
</StackPanel>

如果可能, AGrid旨在使其子代填满所有可用空间。

你正在设置Height="Auto"对所有行进行设置,这意味着默认情况下,行将仅占用渲染控件所需的空间量。然而,由于 a 的Grid工作方式,它会尝试拉伸其中至少一个行以填充所有可用空间。

通常,这种拉伸是平等地完成的,所有行都分配了等量的额外空间,正如您在设计时窗口中看到的那样。但是由于您的第二列只有两个对象,一个带有RowSpan=3,看起来在运行时它决定在组合的 1-2-3 行和第 4 行之间平均分配额外的空间。

为避免这种行为,请确保至少指定一个*高度行来占用所有剩余空间,即使这是底部的空白行。

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="16*"/>
    <ColumnDefinition Width="10*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/> <!-- 5th row to take up all available space -->
</Grid.RowDefinitions>

或切换到Panel不具有此行为的其他对象,例如DockPanelwith LastChildFill="False",或StackPanel

于 2013-05-01T13:47:33.327 回答