我需要以编程方式将具有多个控件的新行添加到网格中,并且这些行和控件也需要在一段时间后删除。问题是,每当删除一行(不是最后一行)时,几行可能会重叠。
初始状态
第0行被删除后
要复制问题,请尝试使用以下步骤的小型wpf应用程序:
的xml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="MainGrid">
</Grid>
</Window>
C#代码:
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
// secondary grid
Grid _sGrid = new Grid();
public MainWindow()
{
InitializeComponent();
SizeToContent = SizeToContent.Height;
// divid the initial grid into two rows.
MainGrid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
MainGrid.RowDefinitions.Add(new RowDefinition());
// add a stack panel to the top row.
var sp = new StackPanel();
Grid.SetRow(sp, 0);
// add a "add a new row" button to the stack panel.
var btn = new Button { Content = "add a new row" };
btn.Click += AddRow;
sp.Children.Add(btn);
// add a secondary grid to the bottom row.
Grid.SetRow(_sGrid, 1);
// add controls
MainGrid.Children.Add(sp);
MainGrid.Children.Add(_sGrid);
}
private int _rowCount;
private int _rowSerialNo;
public void AddRow(object sender, RoutedEventArgs e)
{
// add a row in the secondary grid, set height to auto
var rd = new RowDefinition {Height = GridLength.Auto};
_sGrid.RowDefinitions.Add(rd);
// add a label to the row
var lbl = new Label {Content = $"This is row {_rowSerialNo}"};
Grid.SetRow(lbl,_rowCount);
_sGrid.Children.Add(lbl);
// add a button to the top row of the main grid for deleting this new row
var btn = new Button {Content = $"del row {_rowSerialNo}"};
btn.Click += DelRow;
(MainGrid.Children[0] as StackPanel).Children.Add(btn);
// set resources to make it easier to clear all contents in the row
btn.Resources.Add("rd", rd);
btn.Resources.Add("lbl",lbl);
// advance row count
_rowCount++;
_rowSerialNo++;
}
private void DelRow(object sender, RoutedEventArgs e)
{
// remove contents
_sGrid.Children.Remove((UIElement)(sender as Button).Resources["lbl"]);
// remove row definition
_sGrid.RowDefinitions.Remove((RowDefinition)(sender as Button).Resources["rd"]);
// remove the delete button
(MainGrid.Children[0] as StackPanel).Children.Remove((UIElement)sender);
_rowCount--;
}
}
}
我正在使用VS2015社区
答案 0 :(得分:1)
这是一个快速的MVVM实现,它看起来就像你在做什么。这就是我对使用ItemsControl的意思。有更多的代码行,但它几乎都是声明性的样板文件,因此很难弄错。
此方法的价值在于您可以在集合中添加和删除项目,并且视图会自动更新以反映集合的当前内容。添加项目只需一个简单步骤:添加项目。删除它只需一个简单步骤:删除该项目。如果您更改项目的显示方式,则通过更改XAML来完成;它与如何添加或删除项目无关。
如果您对其中的任何方法有任何疑问,请询问。
XAML:
<StackPanel>
<Button Command="{Binding AddRowItemCommand}">Add Row</Button>
<ItemsControl
ItemsSource="{Binding RowItems}"
>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Content="{Binding Text}"
ContentStringFormat="{}Delete {0}"
Command="{Binding DataContext.RemoveRowItemCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
CommandParameter="{Binding}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl
ItemsSource="{Binding RowItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Text}" ContentStringFormat="{}This is {0}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
“Viewmodels”:从技术上讲,它们不是真正的视图模型,因为它们不需要引发INotifyPropertyChanged.PropertyChanged
。
public class MainViewModel
{
public MainViewModel()
{
RemoveRowItemCommand = new DelegateCommand<RowItem>(RemoveRowItem);
AddRowItemCommand = new DelegateCommand<object>(AddRowItem);
}
public ObservableCollection<RowItem> RowItems { get; } = new ObservableCollection<RowItem>();
public ICommand RemoveRowItemCommand { get; private set; }
public ICommand AddRowItemCommand { get; private set; }
public void RemoveRowItem(RowItem rowItem)
{
RowItems.Remove(rowItem);
}
private int _nextRowItemID = 0;
public void AddRowItem(object unused)
{
RowItems.Add(new RowItem { Text = $"Row {++_nextRowItemID}" });
}
}
public class DelegateCommand<TParam> : ICommand
{
public DelegateCommand(Action<TParam> exec)
{
_execute = exec;
}
public event EventHandler CanExecuteChanged;
private Action<TParam> _execute;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_execute?.Invoke(parameter == null ? default(TParam) : (TParam)parameter);
}
}
public class RowItem
{
public String Text { get; set; }
}
代码背后:
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}