【问题标题】:How to bind a many-to-many relation in WinForms?如何在 WinForms 中绑定多对多关系?
【发布时间】:2018-10-13 23:17:15
【问题描述】:

我有以下数据集:

ProductPart 表可以使用这些 DataGridViews 进行编辑:

当用户双击产品网格中的一行时,会打开以下表单:

左栏应该列出与该产品相关的部件。右栏应该列出所有其他部分。使用 > 按钮,用户应该能够选择哪些部件属于当前产品。

我用一对多的关系做了类似的事情,而且效果很好。代码如下:

public partial class ProductPartsForm : Form
{
    private int _productID;
    private DataSet1 _data;

    public ProductPartsForm(DataSet1 data, DataRowView productRowView)
    {
        var productRow = (DataSet1.ProductRow)productRowView.Row;
        _productID = productRow.ID;
        _data = data;
        InitializeComponent();
        productBindingSource.DataSource = productRowView;
        assignedPartBindingSource.DataSource = productBindingSource;
        assignedPartBindingSource.DataMember = "FK_Product_Part";
        assignedPartsListBox.DisplayMember = "Name";
        unassignedPartBindingSource.DataSource = _data;
        unassignedPartBindingSource.DataMember = "Part";
        unassignedPartsListBox.DisplayMember = "Name";
        unassignedPartBindingSource.Filter = $"isnull(ProductID, 0) = 0";
    } 

    private void assignButton_Click(object sender, EventArgs e)
    {
        var partRowView = (DataRowView)unassignedPartBindingSource.Current;
        var partRow = (DataSet1.PartRow)partRowView.Row;
        var productRowView = (DataRowView)productBindingSource.Current;
        var productRow = (DataSet1.ProductRow)productRowView.Row;
        partRow.ProductRow = productRow;
        UpdateUI();
    }

    private void unassignButton_Click(object sender, EventArgs e)
    {
        var partRowView = (DataRowView)assignedPartBindingSource.Current;
        var partRow = (DataSet1.PartRow)partRowView.Row;
        partRow.SetProductIDNull();
        UpdateUI();
    }

    private void UpdateUI()
    {
        assignedPartsListBox.Refresh();
        unassignedPartsListBox.Refresh();
        assignButton.Enabled = unassignedPartsListBox.Items.Count > 0;
        unassignButton.Enabled = assignedPartsListBox.Items.Count > 0;
    }
}

对于多对多关系,有两件事我无法解决:

  • 左列不显示部件的名称。它应该显示小写字母,如右列;相反,它显示字符串System.Data.DataRowView。我想使用某种查找来解决此问题,但我不知道如何。
  • 当您按下<< 时,选定的部分会停留在右列而不是移动到左列。如果您尝试使用相同的部分再次按<<,则会收到以下错误:

    System.Data.ConstraintException: 'Column 'ProductID, PartID' 被限制为唯一。值 '-4, -3' 已经存在。'

    (这是可以理解的)。我认为这可以使用过滤器表达式来解决,但我不确定如何编写它以及如何在每次更改后自动更新右列。

有没有人做过类似的事情并且可以帮助我指出正确的方向?

【问题讨论】:

  • 如果您可以发布单独的问题而不是将您的问题合并为一个问题,则最好。这样,它可以帮助人们回答您的问题,也可以帮助其他人至少寻找您的一个问题。谢谢!
  • 我不知道如何分解它。我有点希望整个问题会有某种教科书式的解决方案;类似于 UI 的主细节样式,但用于多对多关系而不是一对多。我会尽量缩小范围。
  • 好吧,你至少应该edit 这个问题来显示<<>> 按钮的点击事件处理程序,以及productBindingSource 引用的表。
  • “我试图改写这个问题。新问题在这里。”,请不要问重复的问题!删除重复项并使用重复项的信息编辑此问题

标签: c# winforms data-binding ado.net dataset


【解决方案1】:

这是我最终想出的。关键函数是UpdateFilters,它创建分配给当前产品的部件ID列表,然后使用INNOT IN运算符“手动”过滤这两列。

public partial class ProductPartsForm : Form
{
    private int _productID;
    private DataSet1 _data;

    public ProductPartsForm(DataSet1 data, DataRowView productRowView)
    {
        var productRow = (DataSet1.ProductRow)productRowView.Row;
        _productID = productRow.ID;
        _data = data;
        InitializeComponent();
        productBindingSource.DataSource = productRowView;
        assignedPartBindingSource.DataSource = _data;
        assignedPartBindingSource.DataMember = "Part";
        assignedPartsListBox.DisplayMember = "Name";
        unassignedPartBindingSource.DataSource = _data;
        unassignedPartBindingSource.DataMember = "Part";
        unassignedPartsListBox.DisplayMember = "Name";
    }

    private void ProductPartsForm_Load(object sender, EventArgs e)
    {
        UpdateFilters();
        UpdateUI();
    }

    private void assignButton_Click(object sender, EventArgs e)
    {
        var partRowView = (DataRowView)unassignedPartBindingSource.Current;
        var partRow = (DataSet1.PartRow)partRowView.Row;
        var productRowView = (DataRowView)productBindingSource.Current;
        var productRow = (DataSet1.ProductRow)productRowView.Row;
        _data.ProductPart.AddProductPartRow(productRow, partRow);
        UpdateFilters();
        UpdateUI();
    }

    private void unassignButton_Click(object sender, EventArgs e)
    {
        var partRowView = (DataRowView)assignedPartBindingSource.Current;
        var partRow = (DataSet1.PartRow)partRowView.Row;
        var productPartRow = _data.ProductPart
            .Single(pp => pp.ProductID == _productID && pp.PartID == partRow.ID);
        _data.ProductPart.RemoveProductPartRow(productPartRow);
        UpdateFilters();
        UpdateUI();
    }

    private void UpdateFilters()
    {
        var assignedIds = _data.ProductPart
            .Where(pp => pp.ProductID == _productID)
            .Select(pp => pp.PartID.ToString());
        if (assignedIds.Any())
        {
            assignedPartBindingSource.Filter = $"ID IN ({string.Join(",", assignedIds)})";
            unassignedPartBindingSource.Filter = $"ID NOT IN ({string.Join(",", assignedIds)})";
        }
        else
        {
            assignedPartBindingSource.Filter = "FALSE";
            unassignedPartBindingSource.RemoveFilter();
        }
    }

    private void UpdateUI()
    {
        assignedPartsListBox.Refresh();
        unassignedPartsListBox.Refresh();
        assignButton.Enabled = unassignedPartsListBox.Items.Count > 0;
        unassignButton.Enabled = assignedPartsListBox.Items.Count > 0;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-02
    • 1970-01-01
    • 1970-01-01
    • 2019-10-19
    • 2016-12-10
    • 2020-11-12
    相关资源
    最近更新 更多