我有一个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
答案 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
备注强>
LookUp
的时间很短 - 几乎无法衡量DataTable
是针对这类事情做的,b)行显示时,根据需要完成。如果用户从不滚动那么远,可能永远不会处理第19,999行。DataTable
添加一个布尔列并在其上循环。如果要将列隐藏在用户之外,该列可以是不可见的。
DataTable
中的75k行以设置标记需要 591毫秒。您希望在之前将DataSource
设置为{{1}},以防止更改数据,从而导致控件中出现各种事件。通常,收集最大RevCode标志甚至标记过期行的时间对于创建数据源来说是一个微不足道的增量。
结果:
数据视图按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