在运行时添加和删除网格行
Add and remove Grid rows at runtime
我正在尝试创建一个带有网格的布局,其中有一个“+”按钮用于添加新行以输入内容,并且在每个新行旁边有一个“-”按钮用于删除该行。
我在谷歌上搜索了很远,但没有发现除了在运行时删除 XAML 网格行之外的任何事情。
启动时的静态布局:
<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);
}
添加行有效,但删除行有...有趣的结果。首先最值得注意的是“+”按钮覆盖了最后一个“-”按钮,所以整个东西变得无法使用,我不知道为什么......
目标是保持上面屏幕截图中的布局,以便您可以在任意位置添加和删除行。
您正在将添加按钮的行设置为 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
我正在尝试创建一个带有网格的布局,其中有一个“+”按钮用于添加新行以输入内容,并且在每个新行旁边有一个“-”按钮用于删除该行。
我在谷歌上搜索了很远,但没有发现除了在运行时删除 XAML 网格行之外的任何事情。
启动时的静态布局:
<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);
}
添加行有效,但删除行有...有趣的结果。首先最值得注意的是“+”按钮覆盖了最后一个“-”按钮,所以整个东西变得无法使用,我不知道为什么...... 目标是保持上面屏幕截图中的布局,以便您可以在任意位置添加和删除行。
您正在将添加按钮的行设置为 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