这就是我正在尝试做的事情:
在表单上,我有一个 DataGridView(主视图),绑定到 BindingSource,绑定到 DataSet 内的单个 DataTable。
还有一个“详细信息”部分,其中包含绑定到当前主记录中的字段的单独编辑控件(TextBox、DateTimePicker 等)。这一切都很好。
每个“主”行都有两个关联的“子集合”。这些是在数据集设计器中使用“关系和外键约束”连接到父级的附加表中的行。
每个子集合都有一个 DataGridView,绑定到 BindingSource,绑定到主绑定源中的外键关系。
所以,整体表单布局为Parent-Grid、Parent-detail、Child1-Grid、Clild2-Grid。
在查看/编辑记录时,这一切都非常有效,但在尝试创建新记录时,它非常接近工作,但又不完全是。
例如,我添加一个新的主行(通过单击其 BindingNavigator 上的“添加”)。出现行。 我向第一个子集合添加一行(通过单击其 BindingNavigator 上的“添加”)。出现行。我向第二个子集合添加一行。出现行。
我现在编辑详细信息部分中的主字段之一,然后噗!我在子集合中的新行消失了。或者,我单击“保存”保存所有更改,新的子行就会消失。或者我添加多行,当我保存时,最后一行消失。顺便说一句 - 所有这些消失都发生在将 DataSet 保存到数据库之前 - 这是 DataGridView、BindingSource 等之间的所有交互,全部通过设计器生成的代码。
我是否对 Windows 窗体中的数据绑定要求太多,或者在编辑父子集合时是否缺少一些基本的东西?
这似乎与数据绑定相关。由于您使用的是 .NET Framework 4.8,因此这里有一些仅基于您的陈述的建议,不包括任何其他限制。
Windows Presentation Foundation:您仍然可以将 WPF 与 .NET Framework 4.8 结合使用。与 Windows 窗体相比,WPF 提供了更好的数据绑定支持和更现代的桌面应用程序构建方法。
这里有一些建议:
在表单后面的代码中编写处理逻辑的代码。你可以 直接处理数据。请参阅接下来的示例代码。
您可以尝试 Windows Presentation Foundation。
我还没有看到你的 WinForm 代码,但你可以看一下下面的代码,看看它是否可以引导你走向正确的方向:
// Plain event-handling sameple.
using System;
using System.Data;
using System.Windows.Forms;
public partial class MainForm : Form
{
private DataTable masterTable;
private DataTable child1Table;
private DataTable child2Table;
public MainForm()
{
InitializeComponent();
InitializeData();
BindMasterGrid();
}
private void InitializeData()
{
// This is from your example above
masterTable = myDataSet.Tables["Master"];
child1Table = myDataSet.Tables["Child1"];
child2Table = myDataSet.Tables["Child2"];
}
private void BindMasterGrid()
{
// I think your issue is binding related so bind the master
// DataGridView to the master DataTable
dataGridViewMaster.DataSource = masterTable;
// Handle the CurrentCellChanged event to sync child
// DataGridViews with the selected master row
dataGridViewMaster.CurrentCellChanged += (sender, e) =>
{
// See the code for the next...
UpdateChildGrids();
};
}
private void UpdateChildGrids()
{
// Get the selectedMasterRow in the grid
DataRowView selectedMasterRow =
dataGridViewMaster.CurrentRow?.DataBoundItem as DataRowView;
// This is something to try. Bind the child DataGridViews
// to filtered DataView based on the selected master row
if (selectedMasterRow != null)
{
int masterId = Convert.ToInt32(selectedMasterRow["MasterId"]);
DataView child1View = new DataView(child1Table);
child1View.RowFilter = $"MasterId = {masterId}";
dataGridViewChild1.DataSource = child1View;
DataView child2View = new DataView(child2Table);
child2View.RowFilter = $"MasterId = {masterId}";
dataGridViewChild2.DataSource = child2View;
}
else
{
// Clear child DataGridViews if no master row is selected
dataGridViewChild1.DataSource = null;
dataGridViewChild2.DataSource = null;
}
}
// The rest of your code if needed...
}
检查这个答案。希望这有帮助。