【问题标题】:Add and remove Grid rows at runtime在运行时添加和删除 Grid 行
【发布时间】:2019-01-27 14:44:08
【问题描述】:

我正在尝试创建一个带有网格的布局,其中您有一个“+”按钮来添加新行以输入内容,并且在每个新行旁边有一个“-”按钮来删除该行。

我已经在谷歌上搜索了很多,但没有发现任何比在运行时删除 XAML Grid 行更重要的东西。

启动时的静态布局:

<Grid Grid.Row="0" Margin="0" VerticalAlignment="Top" Name="GridSource">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="75" />
        <ColumnDefinition Width="150" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <TextBlock Grid.Column="0" Grid.Row="0" Name="lblSource0" Text="Source:" Margin="5" />
    <ComboBox Grid.Column="1" Grid.Row="0" Name="cmboSource0" Margin="5" SelectionChanged="CmboSource_SelectionChanged" />
    <TextBox Grid.Column="2" Grid.Row="0" Name="txtSource0" TextWrapping="NoWrap" Margin="5" IsReadOnly="True" />
    <Button Grid.Column="3" Grid.Row="0" Name="btnSource0" Content="..." Width="50" Margin="5" />
    <Button Grid.Column="4" Grid.Row="1" Name="btnAddSource" Content="+" Width="50" Margin="5" Click="BtnAddSource_Click" Height="32" />
</Grid>

添加和删除行的逻辑:

private void BtnAddSource_Click(object sender, RoutedEventArgs e)
{
    AdditionalSourceCounter++;
    string Name = "Source" + AdditionalSourceCounter.ToString();
    GridSource.RowDefinitions.Add(new RowDefinition()); //add new row to Grid
    Grid.SetRow(btnAddSource, GridSource.RowDefinitions.Count); //move "add Source"-button to last row

    TextBlock newLabel = new TextBlock();
    newLabel.Name = "lbl" + Name;
    newLabel.Text = "Source:";
    newLabel.Margin = new Thickness(5);
    GridSource.Children.Add(newLabel); //add new object to form
    Grid.SetColumn(newLabel, 0);
    Grid.SetRow(newLabel, AdditionalSourceCounter);

    ComboBox newComboBox = new ComboBox();
    newComboBox.Name = "cmbo" + Name;
    newComboBox.Margin = new Thickness(5);
    GridSource.Children.Add(newComboBox); //add new object to form
    for (int i = 0; i < Data.SourceTypes.Count; i++) //add items from SourceTypes-list to ComboBox
        newComboBox.Items.Add(Data.SourceTypes[i]);
    newComboBox.SelectedIndex = 0;
    newComboBox.SelectionChanged += CmboSource_SelectionChanged;
    Grid.SetColumn(newComboBox, 1);
    Grid.SetRow(newComboBox, AdditionalSourceCounter);

    TextBox newTextBox = new TextBox();
    newTextBox.Name = "txt" + Name;
    newTextBox.TextWrapping = TextWrapping.NoWrap;
    newTextBox.Margin = new Thickness(5);
    newTextBox.IsReadOnly = true;
    GridSource.Children.Add(newTextBox); //add new object to form
    Grid.SetColumn(newTextBox, 2);
    Grid.SetRow(newTextBox, AdditionalSourceCounter);

    Button newButton = new Button();
    newButton.Name = "btn" + Name;
    newButton.Content = "...";
    newButton.Width = 50;
    newButton.Margin = new Thickness(5);
    GridSource.Children.Add(newButton); //add new object to form
    Grid.SetColumn(newButton, 3);
    Grid.SetRow(newButton, AdditionalSourceCounter);

    Button newButtonRemove = new Button();
    newButtonRemove.Name = "btnRemove" + Name;
    newButtonRemove.Content = "-";
    newButtonRemove.Width = 50;
    newButtonRemove.Margin = new Thickness(5);
    newButtonRemove.Click += BtnRemoveSource_Click;
    GridSource.Children.Add(newButtonRemove); //add new object to form
    Grid.SetColumn(newButtonRemove, 4);
    Grid.SetRow(newButtonRemove, AdditionalSourceCounter);
}

private void BtnRemoveSource_Click(object sender, RoutedEventArgs e)
{
    AdditionalSourceCounter--;
    var callingButton = (Button)sender;
    int rowNumber = Grid.GetRow(callingButton);
    int callingButtonIndex = GridSource.Children.IndexOf(callingButton);
    GridSource.Children.RemoveAt(callingButtonIndex);
    GridSource.Children.RemoveAt(callingButtonIndex - 1);
    GridSource.Children.RemoveAt(callingButtonIndex - 2);
    GridSource.Children.RemoveAt(callingButtonIndex - 3);
    GridSource.Children.RemoveAt(callingButtonIndex - 4);
    GridSource.RowDefinitions.RemoveAt(rowNumber);
    Grid.SetRow(btnAddSource, GridSource.RowDefinitions.Count);
}

添加行有效,但删除行有……有趣的结果。首先最值得注意的是“+”按钮覆盖了最后一个“-”按钮,所以整个东西变得无法使用,我不知道为什么...... 目标是布局与上面的屏幕截图保持一致,以便您可以在任意位置添加和删除行。

【问题讨论】:

    标签: c# uwp uwp-xaml


    【解决方案1】:

    您正在将添加按钮的行设置为GridSource.RowDefinitions.Count。但是,这比您的Grid 中实际存在的行数多一。行数从 0 到 Count - 1,因此最后一行是 GridSource.RowDefinitions.Count-1。发生的情况是Grid 找不到索引为Count 的行,所以它只是将按钮放在Count-1 行中,因此按钮覆盖了最后一行的- 按钮。

    如果你检查你的静态代码,你会发现你有一个额外的行,只有加号按钮。你也必须在这里复制它。

    此外,如果您删除了 Grid 中间的一行,则您正确地删除了它的项目,但您还需要将所有下一个元素向上移动一行 - 因此您需要将它们的 Grid.Row 属性减少一。

    private void BtnRemoveSource_Click(object sender, RoutedEventArgs e)
    {
        AdditionalSourceCounter--;
        var callingButton = (Button)sender;
        int rowNumber = Grid.GetRow(callingButton);
        int callingButtonIndex = GridSource.Children.IndexOf(callingButton);
        foreach ( var child in GridSource.Children.ToArray() )
        {
            var childRow = (int)child.GetValue(Grid.RowProperty);
            if (childRow == rowNumber)
            {
                //this child should be removed
                GridSource.Children.Remove(child); 
            }
            else if (childRow > rowNumber)
            {
                //move items on next rows one row up
                child.SetValue(Grid.RowProperty, childRow - 1);
            }
        }
        GridSource.RowDefinitions.RemoveAt(rowNumber);
        Grid.SetRow(btnAddSource, GridSource.RowDefinitions.Count - 1);
    }
    

    请注意,您可以考虑使用StackPanel,而不是这个冗长且容易出错的代码,其中每个项目都是Grid,只有一行,列与您当前的代码匹配 - 在这种情况下,您可以删除整个项目来自StackPanel,并且不必关心修复Row 值和RowDefinitions

    更好 - 您可以使用自定义 DataTemplate 将代码重写为 ListView

    【讨论】:

    • 非常感谢您的全面回答!我想过放弃并使用堆栈面板。问题是:如果我使用不同的网格,列的宽度不会相同,对吧?那看起来会很可怕。我从未使用过数据模板,这可以解决我的问题吗?
    • 这取决于您如何调整列的大小。如果您对所有列使用星号大小或绝对大小,则大小将相同,因为可用空间相同。自动更成问题,但是如果所有自动单元格在所有行上都包含相同的内容,那么您就可以了
    • 带有数据模板的列表视图更加方便,因为您只需提供数据,控件就会自动生成带有模板化控件的项目。删除行就像从绑定集合中删除项目一样简单。然而,这是一个相当复杂的主题,所以我建议查看文档,尤其是 ListView 和数据绑定主题
    • 我一定会检查 DataTemplates。毕竟我不想编写不必要的复杂代码。谢谢指点!
    • 很高兴它有帮助:-)。编码愉快!
    猜你喜欢
    • 2012-02-24
    • 2016-11-25
    • 1970-01-01
    • 1970-01-01
    • 2022-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-06
    相关资源
    最近更新 更多