C# 删除包含动态文本框/按钮/网格的行

4

我已经测试了一些动态文本框和按钮的内容,将项目添加到我的网格中非常顺利,但如果我想要删除它,则会出现一些问题。有时候一行是空的,我的添加按钮消失或者我的程序崩溃。

我做错了什么或者我错过了什么?

C# 代码:

    public MainWindow()
    {
        InitializeComponent();
    }

    int Numberic = 0;
    private void NewButton_Click(object sender, RoutedEventArgs e)
    {
        #region Row and Numberic
        Numberic++;
        RowDefinition ROW = new RowDefinition();
        GridLength Height = new GridLength(59);
        ROW.Height = Height;

        MainGrid.RowDefinitions.Add(ROW);
        #endregion

        #region Set new Button Location
        int ButtonLocation = Grid.GetRow(NewButton);
        Grid.SetRow(NewButton, ButtonLocation + 1);
        #endregion

        #region Create TextBox
        TextBox CreateTextBox = new TextBox();
        CreateTextBox.Name = "NewTextBox_" + Numberic;
        CreateTextBox.Width = 438;
        CreateTextBox.Height = 35;
        CreateTextBox.Margin = new Thickness(53, 12, 0, 0);
        CreateTextBox.HorizontalAlignment = HorizontalAlignment.Left;
        CreateTextBox.VerticalAlignment = VerticalAlignment.Top;

        CreateTextBox.FontSize = 15;
        CreateTextBox.HorizontalContentAlignment = HorizontalAlignment.Left;
        CreateTextBox.VerticalContentAlignment = VerticalAlignment.Center;

        MainGrid.Children.Add(CreateTextBox);
        Grid.SetRow(CreateTextBox ,ButtonLocation);
        #endregion

        #region Create Button
        Button CreateButton = new Button();
        CreateButton.Name = "NewButton_" + Numberic;
        CreateButton.Width = 35;
        CreateButton.Height = 35;
        CreateButton.Margin = new Thickness(12, 12, 0, 0);
        CreateButton.HorizontalAlignment = HorizontalAlignment.Left;
        CreateButton.VerticalAlignment = VerticalAlignment.Top;

        CreateButton.Content = "-";
        CreateButton.FontSize = 20;
        CreateButton.FontWeight = FontWeights.Bold;
        BrushConverter BC = new BrushConverter();
        CreateButton.Background = (Brush)BC.ConvertFrom("#FFDB0000");
        CreateButton.Foreground = Brushes.White;
        CreateButton.BorderBrush = Brushes.Transparent;

        CreateButton.Click += new RoutedEventHandler(Delete_OnClick);

        MainGrid.Children.Add(CreateButton);
        Grid.SetRow(CreateButton, ButtonLocation);
        #endregion
    }

    private void Delete_OnClick(object sender, RoutedEventArgs e)
    {
        Button SelectedButton = (Button)sender;
        int SelectedRow = Grid.GetRow(SelectedButton);

        string[] Number = SelectedButton.Name.Split('_');
        string TextBoxName = "NewTextBox" + "_" + Number[1];
        TextBox SelectedTextbox = (TextBox)LogicalTreeHelper.FindLogicalNode(MainGrid, TextBoxName);

        MainGrid.Children.Remove(SelectedTextbox);
        MainGrid.Children.Remove(SelectedButton);

        //Numberic--;
        MainGrid.RowDefinitions.RemoveAt(SelectedRow);
    }

XAML 代码:

<Grid Name="MainGrid" ShowGridLines="True" OpacityMask="Black" Background="#FFEDEDED">
    <Grid.RowDefinitions>
        <RowDefinition Height="59" />
    </Grid.RowDefinitions>
    <Button Content="+" Height="35" HorizontalAlignment="Left" Margin="12,12,0,0" Name="NewButton" VerticalAlignment="Top" Width="35" BorderBrush="{x:Null}" Foreground="White" Background="#FF727272" FontWeight="Bold" FontSize="20" Click="NewButton_Click" />
</Grid>

谢谢你,Tkay。

3
为什么你要动态地添加/删除控件?考虑将你的控件放在一个“网格”或其他容器中,并在用户不需要看到它时将其Visibility属性更改为Collapsed - Mike Eason
你是说为什么我要添加和删除行吗?我想这样做会有一个无限添加系统。 - Tkay
1
我相信@MikeEason的意思是“为什么你在使用WPF时像使用WinForms一样?”在WPF中,我们通常使用XAML和数据绑定,而不是从代码后台手动添加UI元素。如果您使用了数据绑定,则删除数据绑定的Textbox/Grid就像从集合中删除对象一样简单。 - Sheridan
2个回答

1

WPF的ItemsControl是在视图中显示可变数量项目的正确方式。

许多控件都继承自ItemsControl,例如ComboBox本身,或者DataGrid,或者ListBox... 但在这个示例中,我将直接使用ItemsControl,因为您尝试的操作不需要任何额外的功能。

首先是XAML

    <Grid Name="MainGrid" OpacityMask="Black" Background="#FFEDEDED">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <ItemsControl x:Name="MyItemsControl">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Button Content="-" Height="35" HorizontalAlignment="Left" Margin="12,12,0,0" Name="NewButton" VerticalAlignment="Top" Width="35" BorderBrush="{x:Null}" Foreground="White" Background="#FFDB0000" FontWeight="Bold" FontSize="20" Click="Delete_OnClick" />
                        <TextBox Width="438" Height="35" Margin="6,12,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="15" HorizontalContentAlignment="Left" VerticalContentAlignment="Center" />
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

        <Button Grid.Row="1" Content="+" Height="35" HorizontalAlignment="Left" Margin="12,12,0,0" Name="NewButton" VerticalAlignment="Top" Width="35" BorderBrush="{x:Null}" Foreground="White" Background="#FF727272" FontWeight="Bold" FontSize="20" Click="NewButton_Click" />
    </Grid>

我已经将“-”按钮和TextBox的定义放在ItemTemplate中。这个模板将被ItemsControl重复使用,每当我们添加一个项目时。
现在,是代码后台:
public partial class MainWindow : Window
{
    int Numberic = 0;

    private void NewButton_Click(object sender, RoutedEventArgs e)
    {
        var item = new Item();
        item.Id = ++Numberic;
        MyItemsControl.Items.Add(item);
    }

    private void Delete_OnClick(object sender, RoutedEventArgs e)
    {
        Button SelectedButton = (Button)sender;
        var item = SelectedButton.DataContext;
        MyItemsControl.Items.Remove(item);
    }
}

如您所见,这种方法比之前的方式简单得多且更加清晰。大部分逻辑由ItemsControl处理,您只需将项目添加删除到/从中即可。
我已经为我们的ItemsControl使用了自定义类(Item)作为其项目,但它可以是任何您想要的。在这种情况下,Item的定义仅为:
public class Item
{
    public int Id { get; set; }
}

请检查在Delete_OnClick方法中,我使用DataContext属性来检索当前的Item实例。
这是因为当您将对象添加到ItemsControl中时,它会创建相应的“可视项”,并将添加的对象分配为此“可视项”和控件的DataContext。这样,您可以直接创建绑定到其属性等。

下一步将是使用MVVM和数据绑定:P 寻找有关绑定的信息以及如何使用它们来填充您的ItemsControl,为您的按钮设置命令(而不是使用Click事件),并将您的TextBlocks和TextBoxes连接到实际数据。 - almulo
这个很好用,就像你说的那样,代码比我的少多了。谢谢你的帮助,期待数据绑定的到来。 :) - Tkay
你有没有推荐学习C# WPF的网站?由于我的知识和糟糕的英语水平,我找不到关于数据绑定或命令的相关内容。也许是我太盲目了。 - Tkay
我建议你从这里开始:http://www.wpftutorial.net/GettingStarted.html ;) 还有这里关于数据绑定:http://www.wpftutorial.net/DataBindingOverview.html - almulo

0

首先,我强烈建议您考虑使用ItemsControl来处理这种情况。这样做会更容易和更清晰。如果您不知道如何操作,请告诉我,我会尝试发布一个示例。

但是回答您最初的问题...发生的情况是,您从Grid中删除了RowDefinition,但没有相应地更新其余控件的Grid.Row属性。

例如,如果您创建了3行,则原始的“+”按钮现在位于Grid.Row编号4。

如果您删除了其中一行,则Grid现在只有4个行定义,但是您的“+”按钮仍然分配给Grid.Row 4(不存在)。因此,它被放置在最接近的匹配项Grid.Row编号3上。它不会消失,只是在第3行的“-”按钮下面。


好的,现在我知道我的按钮在哪里了,但是如何正确地移动它们呢?而且我不了解ItemsControl,如果您能给我一个示例就太好了,也许这会帮助我。 - Tkay
好的,我会添加另一个答案,使用ItemsControl在WPF中正确完成此操作 :) - almulo

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