根据与其他行的值比较突出显示DataGridViewRows

时间:2016-12-09 14:49:54

标签: vb.net winforms datagridview

我有一个Part类,其中包含以下代码中的字段列表。我有一个DataGridView控件,我使用NUGET的Advanced DGV(ADGV)DLL进行过滤。我必须在我的winform中加入ADGV。我目前有一个DataGridView,一个表单上的搜索框,以及一个运行以下功能的按钮。我需要遍历所有可见行,收集一个唯一的零件编号列表及其最新版本,然后通过检查每个行的部件号和转速对照最大的清单,为DataGridView中的行着色过时。对于DataGridView中显示的45,000个条目,这需要大约17秒。对于约50个条目,需要约1.2秒。这是非常低效的,但我看不到减少时间的方法。

Sub highlightOutdatedParts()
    'Purpose: use the results in the datagridview control, find the most recent revision of each part, and 
    '           highlight all outdated parts relative to their respective most recent revisions
    'SORT BY PART NUMBER AND THEN BY REV
    If resultsGrid.ColumnCount = 0 Or resultsGrid.RowCount = 0 Then Exit Sub
    Dim stopwatch As New Stopwatch
    stopwatch.Start()
    resultsGrid.Sort(resultsGrid.Columns("PartNumber"), ListSortDirection.Ascending)
    Dim iBag As New ConcurrentBag(Of Part)
    Dim sortedList As Generic.List(Of Part)
    For Each row As DataGridViewRow In resultsGrid.Rows
        If row.Visible = True Then
            Dim iPart As New Part()
            Try
                iPart.Row = row.Cells(0).Value
                iPart.Workbook = CStr(row.Cells(1).Value)
                iPart.Worksheet = CStr(row.Cells(2).Value)
                iPart.Product = CStr(row.Cells(3).Value)
                iPart.PartNumber = CStr(row.Cells(4).Value)
                iPart.ItemNo = CStr(row.Cells(5).Value)
                iPart.Rev = CStr(row.Cells(6).Value)
                iPart.Description = CStr(row.Cells(7).Value)
                iPart.Units = CStr(row.Cells(8).Value)
                iPart.Type = CStr(row.Cells(9).Value)
                iPart.PurchCtgy = CStr(row.Cells(10).Value)
                iPart.Qty = CDbl(row.Cells(11).Value)
                iPart.TtlPerProd = CDbl(row.Cells(12).Value)
                iPart.Hierarchy = CStr(row.Cells(13).Value)
                iBag.Add(iPart)
            Catch ice As InvalidCastException
            Catch nre As NullReferenceException
            End Try
        End If
    Next
    sortedList = (From c In iBag Order By c.PartNumber, c.Rev).ToList()  ' sort and convert to list
    Dim mostUTDRevList As New Generic.List(Of Part)     ' list of most up to date parts, by Rev letter
    For sl As Integer = sortedList.Count - 1 To 0 Step -1   'start at end of list and work to beginning
        Dim query = From entry In mostUTDRevList    ' check if part number already exists in most up to date list
                    Where entry.PartNumber = sortedList(sl).PartNumber
                    Select entry
        If query.Count = 0 Then     ' if this part does not already exist in the list, add.
            mostUTDRevList.Add(sortedList(sl))
        End If
    Next
    'HIGHLIGHT DATAGRIDVIEW ROWS WHERE PART NUMBERS ARE OUT OF DATE
    For Each row As DataGridViewRow In resultsGrid.Rows
        ' if that part with that Rev does not exist in the list, it must be out of date
        Try
            Dim rowPN As String = CStr(row.Cells(4).Value).ToUpper  ' get part number
            Dim rowR As String = CStr(row.Cells(6).Value).ToUpper   ' get Rev
            Dim query = From entry In mostUTDRevList    ' check if that part number with that Rev is in the list.
                        Where entry.PartNumber.ToUpper.Equals(rowPN) AndAlso
                        entry.Rev.ToUpper.Equals(rowR)
                        Select entry
            If query.Count = 0 Then     ' if the part is out of date highlight its' row
                row.DefaultCellStyle.BackColor = Color.Chocolate
            End If
        Catch ex As NullReferenceException
        Catch ice As InvalidCastException
        End Try
    Next
    resultsGrid.Select()
    stopwatch.Stop()
    If Not BackgroundWorker1.IsBusy() Then timertextbox.Text = stopwatch.Elapsed.TotalSeconds.ToString & " secs"
    MessageBox.Show("Highlighting completed successfully.")
End Sub

2 个答案:

答案 0 :(得分:1)

使用数据几乎总是比控件更快。该控件只是向用户显示数据(在网格中)的视图的方法。使用那里的数据需要太多的转换才能有效。然后,使用DGV事件突出显示行

很难说明你正在做什么的所有细节,但看起来像你正在将数据与自身进行比较(而不是定义了最新修订代码的一些具体表格)。也不清楚为什么数据源是集合,ConcurrentBags等。关键是使用针对作业优化的集合。

为了证明,我有一张75,000行的表格;产品代码是从25,000的池中随机选择的,修订代码是随机整数(1-9)。构建DGV数据源(DataTable)后,将从ProductCode-Revision对创建LookUp。这只做了一次:

' form level declaration
Private PRCodes As ILookup(Of String, Int32)

' go thru table
' group by the product code
' create an anon Name-Value object for each, 
'     storing the code and highest rev number
' convert result to a LookUp
PRCodes = dtSample.AsEnumerable.
    GroupBy(Function(g) g.Item("ProductCode"),
            Function(key, values) New With {.Name = key.ToString(), .Value = values.
                                    Max(Of Int32)(Function(j) j.Field(Of Int32)("RevCode"))
                                                      }).
    ToLookup(Of String, Int32)(Function(k) k.Name, Function(v) v.Value)

通过秒表经过的时间: 81毫秒来创建23731项的集合。该代码使用匿名类型为每个产品代码存储Max Revision代码。也可以使用具体类。如果您担心混合套管,请在创建.ToLowerInvariant()(不是LookUp - 请参阅What's Wrong With Turkey?)时使用ToUpper,然后在查找最大转速时再次使用RowPrePaint

然后,不是通过DGV行循环使用If e.RowIndex = -1 Then Return If dgv1.Rows(e.RowIndex).IsNewRow Then Return ' .ToLowerInvariant() if the casing can vary row to row Dim pc = dgv1.Rows(e.RowIndex).Cells("ProductCode").Value.ToString() Dim rv = Convert.ToInt32(dgv1.Rows(e.RowIndex).Cells("RevCode").Value) Dim item = PRCodes(pc)(0) If item > rv Then dgv1.Rows(e.RowIndex).DefaultCellStyle.BackColor = Color.MistyRose End If 事件:

LookUp

备注

  • 创建DataSource需要一些时间,但是要向用户投掷75,000行
  • 创建LookUp的时间很短 - 几乎无法衡量
  • 显示它们没有明显的等待,因为a)DataTable是针对这类事情做的,b)行显示时,根据需要完成。如果用户从不滚动那么远,可能永远不会处理第19,999行。
  • 这一切都适合于为一行着色。如果需要为每行保存Current / NotCurrent状态,请向DataTable添加一个布尔列并在其上循环。如果要将列隐藏在用户之外,该列可以是不可见的。
    • 随机数据导致47,000个过时的RevCodes。处理DataTable中的75k行以设置标记需要 591毫秒。您希望在之前DataSource设置为{{1}},以防止更改数据,从而导致控件中出现各种事件。

通常,收集最大RevCode标志甚至标记过期行的时间对于创建数据源来说是一个微不足道的增量。

结果:

enter image description here

数据视图按ProductCode排序,以便显着降低RevCodes的颜色。

我们肯定无法从一个小片段中了解系统的所有细节和约束 - 即使数据类型和原始数据源也是我们的猜测。但是,这应该为更好的查找方法以及使用数据而不是用户的视图提供一些帮助。

有一件事就是修订代码 - 你的修改代码将它们视为一个字符串。如果这是字母数字,则可能无法正确比较 - " 9"排序/比较高于" 834"或" 1JW"。

另见:
Lookup(Of TKey, TElement) Class
Anonymous Types

答案 1 :(得分:0)

该解决方案部分受到@Plutonix的推动。

Sub highlightOutdatedParts()
    If resultsGrid.ColumnCount = 0 Or resultsGrid.RowCount = 0 Then Exit Sub
    Dim stopwatch As New Stopwatch
    stopwatch.Start()
    resultsGrid.DataSource.DefaultView.Sort = "PartNumber ASC, Rev DESC"
    resultsGrid.Update()
    'HIGHLIGHT DATAGRIDVIEW ROWS WHERE PART NUMBERS ARE OUT OF DATE
    Dim irow As Long = 0
    Do While irow <= resultsGrid.RowCount - 2
        ' if that part with that Rev does not exist in the list, it must be out of date
        Dim utdPN As String = resultsGrid.Rows(irow).Cells(4).Value.ToString().ToUpper()
        Dim utdRev As String = resultsGrid.Rows(irow).Cells(6).Value.ToString().ToUpper()
        Dim iirow As Long = irow + 1
        'If iirow > resultsGrid.RowCount - 1 Then Exit Do
        Dim activePN As String = Nothing
        Dim activeRev As String = Nothing
        Try
            activePN = resultsGrid.Rows(iirow).Cells(4).Value.ToString().ToUpper()
            activeRev = resultsGrid.Rows(iirow).Cells(6).Value.ToString().ToUpper()
        Catch ex As NullReferenceException
        End Try
        Do While activePN = utdPN
            If iirow > resultsGrid.RowCount - 1 Then Exit Do
            If activeRev <> utdRev Then
                resultsGrid.Rows(iirow).DefaultCellStyle.BackColor = Color.Chocolate
            End If
            iirow += 1
            Try
                activePN = resultsGrid.Rows(iirow).Cells(4).Value.ToString().ToUpper()
                activeRev = resultsGrid.Rows(iirow).Cells(6).Value.ToString().ToUpper()
            Catch nre As NullReferenceException
            Catch aoore As ArgumentOutOfRangeException
            End Try
        Loop
        irow = iirow
    Loop
    resultsGrid.Select()
    stopwatch.Stop()
    If Not BackgroundWorker1.IsBusy() Then
        timertextbox.Text = stopwatch.Elapsed.TotalSeconds.ToString & " secs"
        resultcounttextbox.Text = resultsGrid.RowCount - 1 & " results"
    End If
    MessageBox.Show("Highlighting completed successfully.")
End Sub