在下面的代碼的BindingSource後,我有產生EnumerableRowCollection(Of DataRow)
是最終在一個BindingSource.
DataTable的NEWROW()方法將導致LINQ表達的重新評價被用作與AsDataView()
使用LINQ表達代碼第一次循環,沒關係。但是,一旦在IEnumerable
上使用AsDataView()
設置了第一個Control
的BindingSource
,則下一次調用DataTable
上的NewRow()
方法時,它將重新評估LINQ表達式。
Option Explicit On
Option Infer Off
Option Strict On
Public Class Form1
Dim ds As New DataSet()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ds.Tables.Add("Table1")
Dim comparisonInteger As Integer = 12
ds.Tables("Table1").Columns.Add("ID", GetType(Integer))
ds.Tables("Table1").Columns.Add("IntegerValue", GetType(Integer))
ds.Tables("Table1").Columns.Add("StringValue", GetType(String))
ds.Tables("Table1").Rows.Add({1, 47, "row 1"})
ds.Tables("Table1").Rows.Add({2, 2, "row 1"})
ds.Tables("Table1").Rows.Add({3, 7, "row 1"})
ds.Tables("Table1").Rows.Add({4, 6, "row 1"})
For i As Integer = 0 To 2
Dim iterator As Integer = i
Dim tb As New TextBox()
CreateNewRowIfMissing(comparisonInteger+i)
Dim dataValue As EnumerableRowCollection(Of DataRow) = ds.Tables("Table1").AsEnumerable() _
.Where(Function(v) DirectCast(v("IntegerValue"), Integer) = comparisonInteger + iterator)
Dim bs As New BindingSource(dataValue.AsDataView(), Nothing)
Dim b As New Binding("Text", bs, "IntegerValue")
b.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged
tb.DataBindings.Add(b)
tb.Location = New Point(10, 10 * Me.Controls.Count+1)
Me.Controls.Add(tb)
Next
End Sub
Private Sub CreateNewRowIfMissing(comparisonInteger As Integer)
If ds.Tables("Table1").AsEnumerable() _
.Where(Function(v) DirectCast(v("IntegerValue"), Integer) = comparisonInteger) _
.Count() = 0
ds.Tables("Table1").Rows.Add(ds.Tables("Table1").NewRow()) 'Prompts the dataValue IEnumerable to begin evaluating again.
ds.Tables("Table1").Rows(ds.Tables("Table1").Rows.Count-1)("ID") = ds.Tables("Table1").Rows.Count
ds.Tables("Table1").Rows(ds.Tables("Table1").Rows.Count-1)("IntegerValue") = comparisonInteger
ds.Tables("Table1").Rows(ds.Tables("Table1").Rows.Count-1)("StringValue") = "row" & ds.Tables("Table1").Rows.Count.ToString()
End If
End Sub
End Class
爲了澄清,我用一個標準的DataView
有RowFilter
爲BindingSource
,它的工作:
Dim dv As New DataView(ds.Tables("Table1"))
dv.RowFilter = "IntegerValue=" & (comparisonInteger+iteratorValue)
不過,我覺得這可能是更好的利用LINQ來代替。
那麼,這是怎麼回事?爲什麼LINQ表達式DataView
是基於在調用DataTable
的NewRow()
方法時重新評估的?有什麼辦法可以防止這種情況發生?
我本來希望AsDataView()
會產生一個DataView
,其行爲與上述兩行相同。
由於潛在的變通,我發現我可以用這個作爲BindingSource
的DataSource
:
New DataView(dataValue.AsEnumerable().CopyToDataTable())
不過,我很擔心用在這樣的陣容潛在的性能未來,並且如果需要上述行,我不妨使用DataView
和RowFilter
而不是LINQ。
啊,所以'CopyToDataTable'絕對會打破我的DataBinding。在考慮將其作爲替代品之前,可能應該已經進行了測試。無論如何,我確實知道它在IEnumerable下引用同一個表(這是我想要的)。你是說當'DataTable'增加了一個新行時,這會引發'DataView'中的'ListChanged'事件,導致對'DataView'創建的linq表達式進行重新評估?我的理解是否正確? – Interminable
* 1)*您使用'CopyToDataTable'接收的數據包含相同的值,但它是另一個參考。這是一個不同的'DataTable'。 * 2)*當您添加記錄或對其底層DataTable應用任何更改時,將會引發'DataView'的'ListChanged'事件。 * 3)* DataView的'ListChanged'事件導致綁定控件詢問數據,因此包含新行的整個數據將返回到'DataGridView'。例如,如果您將'bs.RaiseListChangedEvents = false'設置爲'DataGridView',您將看不到更改。 –
不要擔心性能。顯示添加到「DataTable」的新記錄不會對性能產生任何負面影響。考慮一下你的需求和你需要的東西。然後根據您的要求選擇解決方案。例如,如果你需要數據綁定到原始記錄,你應該使用'AsDataView'。另外如果你不想顯示新的記錄(我不知道爲什麼),然後應用過濾器到'DataView.RowFilter'。 –