获取DataGrid 以获取合适的数据对象进行操作:
由于DataGrid 对绑定到数据对象的主体进行操作,因此您需要以DataTable 之类的方式跟踪数据。
例如,为 DataTable 类型的 MainWindow 类初始化一个字段并将其命名为相关:
public partial class MainWindow : Window
{
private DataTable _cars = new DataTable("Cars");
然后在您的构造函数中,在初始化窗口组件后,将DataGrid.ItemSource 作为数据视图绑定到 DataTable 的集合:
public MainWindow()
{
InitializeComponent();
dgCars.ItemsSource = _cars.AsDataView();
}
现在,只要您以编程方式向_cars 表添加新行,它们就会反映在DataGrid 中,耶!但是,您希望能够从用户界面对数据进行操作,所以让我们开始吧!
使用来自用户界面的输入对DataTable 中的数据进行操作:
当你想对数据进行操作时,你可以从DataGrid里面的item中获取选择的内容,并使用它们提供的索引从DataTable中移除item,然后重新应用DataView。这就是摘要,但我将更详细地完成示例:
-
在执行我们的逻辑之前,我们需要遍历每个 DataGrid 项目并检查它是否被选中:
for (int i = 0; i < dgCars.Items.Count; i++)
{
if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
{
// This is where we do the magic
}
}
-
但是,我们无法从当前用于提供 DataGrid 的 DataTable 中删除项目,否则我们将遇到 IndexOutOfBounds(可能还有 Enumeration)错误,因此为了安全起见,我们将使用要操作的表的副本:
DataTable result = _cars.Copy(); //New in this step
for (int i = 0; i < dgCars.Items.Count; i++)
{
if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
{
result.Rows.RemoveAt(i); //New in this step
}
}
-
再一次,我们会遇到 IndexOutOfBounds 错误,因为我们正在迭代数据,就好像有 X 的数据量一样,但是每次我们 RemoveAt(i) 时,我们现在都在迭代 X-- 的数量数据的。所以,让我们添加一个计数并跟踪:
int removed = 0; //New in this step
DataTable result = _cars.Copy();
for (int i = 0; i < dgCars.Items.Count; i++)
{
if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
{
//Subtracting `removed` new in this step
result.Rows.RemoveAt(i - removed);
removed++; //New in this step
}
}
-
最后但并非最不重要的一点是,我们将_cars 变量指向堆上的result DataTable 对象,然后重新分配dgCars.ItemSource = _cars.AsDataView() 以更新我们的DataGrid (对此有更复杂的解释,请参阅我的答案的最底部,如果有兴趣):
int removed = 0;
DataTable result = _cars.Copy();
for (int i = 0; i < dgCars.Items.Count; i++)
{
if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
{
result.Rows.RemoveAt(i - removed);
removed++;
}
}
_cars = result; //New in this step
dgCars.ItemSource = _cars.AsDataView(); //New in this step
成品:
我们在这里构建的这个示例允许您从DataGrid 中删除数据,方法是用鼠标选择其上的行,然后单击Click 值等于btnRemove_Click 的按钮。简单的修改和逻辑更改将允许您执行相同的操作来添加、编辑等数据,但我们最初使用的原理是对数据对象(在本例中为 DataTable)进行操作并拥有项目是ItemsSource 的DataGrid。
public partial class MainWindow : Window
{
private DataTable _cars = new DataTable("Cars");
public MainWindow()
{
InitializeComponent();
// THIS WASN'T IN THE BUILD EXAMPLE, BUT AS A BONUS:
// We could ALSO use this opportunity to setup static
// column headers if we know what they are in advance!
_cars.Columns.Add("Year");
_cars.Columns.Add("Make");
_cars.Columns.Add("Model");
dgCars.ItemsSource = _cars.AsDataView();
}
private btnRemove_Click(object sender, RoutedEventArgs e)
{
int removed = 0;
DataTable result = _cars.Copy();
for (int i = 0; i < dgCars.Items.Count; i++)
{
if (dgCars.SelectedItems.Contains(dgCars.Items[i]))
{
result.Rows.RemoveAt(i - removed);
removed++;
}
}
_cars = result;
dgCars.ItemSource = _cars.AsDataView();
}
}
-补充阅读-
在前面的第 4 步中,我提到过:
最后但同样重要的是,我们将把 _cars 变量指向我们的 result
堆上的DataTable对象然后重新分配dgCars.ItemSource = _cars.AsDataView()来更新我们的DataGrid
这是因为_cars 和result 都是从类 实例化的对象,所以它们驻留在堆上。当堆栈上不再有对它们的引用时,堆上的项目将被垃圾收集(从内存中删除)。由于_cars 是我们MainWindow 的一个字段,并且在btnRemove_Click 的范围之外继续存在,所以当我们将其指向DataTable result 时,我们保留对该表的引用,并删除对原始表的引用。因此,当btnRemove_Click 完成时,变量result 被垃圾回收,_cars 使用指向的旧DataTable 被垃圾回收,_cars 现在引用我们创建的新 DataTable 对象。
这个答案要详细得多,上面的 cmets 也值得一读:https://stackoverflow.com/a/80113/13924556