C# WinForms在主-详细信息数据绑定中的多个子网格

ccrfmcuu  于 2023-08-07  发布在  C#
关注(0)|答案(2)|浏览(130)

我想这么做

  • VS 2022,.NET Framework 4.8
  • Windows窗体应用程序
  • 所有的数据处理都是DataSet、DataTables等,全部由设计师生成。

在一个窗体上,我有一个DataGridView(Master),它绑定到BindingSource,绑定到DataSet中的单个DataTable。
还有一个“详细信息”部分,其中包含绑定到当前主记录中的字段的单个编辑控件(TextBox、DateTimePicker等)。这一切都很好。
有两个“子集合”与每个“主”行相关联。这些是在数据集设计器中使用“关系和外键约束”联接到父级的其他表中的行。
每个子集合都有一个绑定到BindingSource的DataGridView,该BindingSource绑定到主绑定源中的外键关系。
因此,整个表单布局是Parent-Grid,Parent-detail,Child 1-Grid,Clild 2-Grid。
在查看/编辑记录时,这一切都很好用,但是当试图创建新记录时,它就很烦人地接近工作,但又不完全是。
例如,我添加了一个新的Master行(通过单击其BindingNavigator上的Add)。行出现。我向第一个子集合添加一行(通过单击其BindingNavigator上的Add)。行出现。我向第二个子集合添加一行。行出现。
我现在编辑细节部分中的一个主字段,然后噗!子集合中的新行将消失。或者单击Save保存所有更改,新的子行将消失。或者我添加了多行,当我保存时,最后一行消失了。顺便说一下-所有这些消失都发生在DataSet保存到数据库之前-这是DataGridView、BindingSource等之间的所有交互,所有这些都是通过设计器生成的代码。
我是不是对Windows窗体中的数据绑定要求太高了,还是在编辑父子集合时缺少了一些基本的东西?

fcy6dtqo

fcy6dtqo1#

这似乎与数据绑定有关。由于您使用的是.NET Framework 4.8,因此这里仅根据您的陈述提供一些建议,不包括任何其他限制。

Windows Presentation Foundation:您仍然可以在.NET Framework 4.8中使用WPF。与Windows窗体相比,WPF为数据绑定提供了更好的支持,并提供了一种更现代的方法来生成桌面应用程序。

以下是一些建议:
1.编写代码以处理表单背后的代码中的逻辑。您可以直接处理数据。请参见下面的示例代码。
1.您可以尝试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...
}

字符串
检查this答案。希望这对你有帮助。

vfhzx4xs

vfhzx4xs2#

这就是我最后做的。

  • 将所有BindingSource数据源设置为服务于整个窗体的一个数据集。我没有将任何东西绑定到“父”表所公开的外键关系。
  • 将每个绑定源的DataMember设置为相应的表。
  • 使用Filter表达式每个子绑定源仅选择与“父”表的当前成员对应的行。在ParentBindingSource.CurrentChanged的事件处理程序中更新Filter表达式,确保将其设置为在没有当前父级时不选择任何内容的表达式。
  • 停止使用BindingNavigator,只使用普通的ToolStrips和按钮。我只需要新建和删除,所以BindingNavigator主要是额外的重量。
  • 通过在设计器生成的DataTable类上直接调用AddXxxxxRow方法来添加新行,并为所有行指定值,以便永远不会出现无效的行内容。
  • 在向表中添加新行时添加互锁,以防止BindingSource.CurrentChanged事件处理程序中的任何操作在插入进行时运行。这似乎是大量奇怪行为的根源,因为在更新表时会引发this和其他事件,因此绑定控件会看到导致各种问题的暂时无效状态,包括DataTable本身的内部一致性故障。
  • 通过调用BindingSource.RemoveCurrent()删除行。
  • 挂钩XxxxxDataTable.XxxxxRowChanged(设计器生成)和BindingSource.ListChanged事件,以检测何时进行了编辑,从而启用ToolStrip中的保存按钮。
  • 我的一些控件包括组合框,这些组合框是绑定到数据集中其他表的数据。这些表可以在窗体使用时重新加载。我不得不解除这些控件与它们的DataRowView的绑定,更新表,然后重新绑定控件。如果没有这一步,控件最终会将所有组合框更改为它们各自的第一项,从而导致对正在构造的“子”行进行虚假编辑。

所以,最后,我实际上保留了设计师制作的大部分数据绑定机制--我“只是”停止使用绑定到外键关系,并自己处理所有的子表过滤。
所有外键更新传播都由设计器生成的DataSet处理,因此删除父行也会透明地删除所有链接的子行,正如您所期望的那样。

相关问题