【问题标题】:Removing duplicates in a List<T> based on selection from DataGridView根据从 DataGridView 中的选择删除 List<T> 中的重复项
【发布时间】:2012-01-17 16:42:41
【问题描述】:

(强制性初学者提醒!我不能保证我会理解你告诉我的一切。)

我有一个程序使用自定义类CheckOrderLineList&lt;T&gt; 通过BindingSource 填充DataGridView。在dataGrid 控件中,我提供了将记录“拆分”为多行以进行拼版的功能。我无法解决这个过程的逆向。

我需要能够在dataGrid 中进行选择,从第一个选择的行开始,然后遍历选择中的每个CheckOrderLine 并将它们与第一行进行比较。

如果它们都匹配,我需要将第一条记录中的数量更改为所有选定行的总和,然后删除多余的行。

这是迄今为止我自己解决的问题:

        int index = 1;
        while (index < rowToJoin)
        {
            _bs.RaiseListChangedEvents = false;

            int first = _bs.Position;
            int second = first++;
            CheckOrderLine current = (CheckOrderLine)_bs[first];
            CheckOrderLine next = (CheckOrderLine)_bs[second];

            if (current.OrderNumber == next.OrderNumber)
            {
                _bs.RemoveAt(second);
            }
            else
            {
                MessageBox.Show("You must select at least two matching rows to join.");
                return;
            }

            _bs.RaiseListChangedEvents = true;
            _bs.ResetBindings(false);
            index++;
        }

这仅在我从下往上选择时才有效,并且仅基于 OrderNumber。为了防止意外,我真的需要检查两行之间的所有字段。在这一点上,能够选择任何方向将是一个奖励。

编辑:我认为我最初还不够清楚。

  1. 我有一种方法可以将一行拆分为 2-5 个新行。
  2. 我的原始代码可以加入任意数量的行,但前提是从下到上选择,并且基于OrderNumber
  3. 除了current.OrderNumber == next.OrderNumber 之外,还有更有效的方法来比较两行吗?我知道我可以将我的所有字段添加到 if 语句中,但我希望它更可重用。
  4. 在任何方向上进行选择都远远落后于在所有字段之间进行比较。

【问题讨论】:

    标签: .net visual-studio-2010 c#-4.0


    【解决方案1】:

    它只在自下而上选择时有效的原因是BindingSource.Current 指向最后一个被选择的项目,所以如果你从自上而下选择,你是在与未选择的项目进行比较。

    您似乎也有一个错误导致您的firstsecond 被反转。您可能无意使用后缀递增操作。

    假设_bs.Position 是 5;

    int first = _bs.Position;  // first is now 5
    int second = first++;  // postfix increment: second is now 5, first is now 6
    

    正如documentation 所说,

    运算的结果是操作数之前的值 增加了

    所以你真的做到了:

    second = first;
    first = first + 1;
    

    看起来你只是想这样做:

    second = first + 1;
    

    在这种情况下可能没有什么不同,但它会使代码非常混乱。


    您尝试做的事情有很多方法。这里也许是一种更直接、更容易理解的方式:

    int count = dgv.SelectedRows.Count;
    
    // DataGridView.SelectedRows is reverse order, so the first selected item is the last item in the list
    var firstSelected = dgv.SelectedRows[count - 1].DataBoundItem as CheckOrderLine;
    int firstOrderNumber = firstSelected.OrderNumber;
    
    // starting at second-last item (second selected row)
    for (int i = count - 2; i >= 0; i--)
    {
        var row = dgv.SelectedRows[i];
        var item = row.DataBoundItem as CheckOrderLine;
        if (item.OrderNumber == firstOrderNumber)
            dgv.Rows.Remove(row);
    }
    

    为简单起见,我省略了更新剩余行和任何错误检查。

    请注意,即使匹配的行不连续,这也会起作用。允许与否由您决定。

    【讨论】:

    • 我知道为什么它只有在我以某种方式选择它时才有效。我完全不知道制作firstsecond 的错误。明天早上我会试一试,看看情况如何。谢谢。
    • 我刚刚试了一下,它完美地解决了方向问题,但它一次只能处理 2 条记录。
    • 这不可能......这段代码中没有任何内容将其限制为两行。你的 gridview 的 SelectionMode 是什么?将其设置为 FullRowSelect 或 RowHeaderSelect。
    • 设置为全行选择。看起来如果我选择了超过 2 个,它一次只会删除 2 个。
    • 我刚刚对此进行了测试,它适用于任意数量的项目,并且将始终保持选中第一个项目,同时删除与之匹配的任何其他项目。我无法猜测为什么它对你的工作方式不同。
    猜你喜欢
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 2019-03-24
    • 2019-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多