我一直在試圖解決一個令人沮喪的問題,就Winforms中的數據綁定問題。在同一個數據源中每行數據綁定一個控件
我有一個數據源,這是一個DataTable
在DataSet
。這DataTable
有三排。我的表單上有三個CheckBox
控件,還有一個Button
。我想將每個CheckBox
綁定到此數據源中的一行,並且只要更新CheckBox
,數據源就會反映Checked
屬性中的值。我還希望通過致電HasChanges()
和致電GetChanges()
正確接收這些更改。
當點擊Button
,EndCurrentEdit()
將被調用並且該數據源,其被結合到,並DataSet
檢查用於使用HasChanges()
方法的變化。
但是,在我嘗試這樣做時,在撥打EndCurrentEdit()
後遇到兩種情況之一。
在第一種情況下,只有第一個CheckBox
檢測到其更改。在第二種情況下,將所有其他CheckBoxes
更新爲CheckBox
的值,該值是在致電EndCurrentEdit()
時最後一次檢查的值。
在調用EndCurrentEdit()
之後,在方案1中查看RowState
值後,只有第一行的狀態爲Modified
。在情景2中,只有第三行的狀態爲Modified
。對於情景2,用戶是否更新了第三個CheckBox
並不重要。
爲了演示我的問題,我創建了一個演示它的簡單示例。
這是一個包含三個CheckBox
控件和一個Button
控件的股票Windows窗體,全部都使用它們的默認名稱。
Option Strict On
Option Explicit On
Public Class Form1
Public ds As DataSet
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
ds = New DataSet()
Dim dt As New DataTable()
dt.Columns.Add("ID", GetType(Integer))
dt.Columns.Add("Selected", GetType(Boolean))
dt.Rows.Add(1, False)
dt.Rows.Add(2, False)
dt.Rows.Add(3, False)
dt.TableName = "Table1"
ds.Tables.Add(dt)
ds.AcceptChanges()
For i As Integer = 1 To 3
Dim bs As New BindingSource()
'After the call to Me.BindingContext(ds.Tables("Table1")).EndCurrentEdit() there are two scenarios:
'Scenario 1 - only changes to the first CheckBox are detected.
'Scenario 2 - when any CheckBox is checked, they all become checked.
'Uncomment the first and comment out the second to see Scenario 1.
'Uncomment the second and comment out the first to see Scenario 2.
'bs.DataSource = New DataView(ds.Tables("Table1")) 'Scenario 1
bs.DataSource = ds.Tables("Table1") 'Scenario 2
bs.Filter = "ID=" & i
Dim db As New Binding("Checked", bs, "Selected")
db.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged
If i = 1
CheckBox1.DataBindings.Add(db)
ElseIf i = 2
CheckBox2.DataBindings.Add(db)
ElseIf i = 3
CheckBox3.DataBindings.Add(db)
End If
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.BindingContext(ds.Tables("Table1")).EndCurrentEdit()
If ds.HasChanges()
MessageBox.Show("Number of rows changed: " & ds.GetChanges().Tables("Table1").Rows.Count)
ds.AcceptChanges()
End If
End Sub
End Class
我已經做了大量的搜索,但一直沒有能夠解決發生了什麼事情,因此完全喪失了工作。感覺就像我想要做的事很簡單,但我懷疑我一定是誤解了某個地方或者錯過了一些關於綁定過程的重要事情。
編輯
它已經在第二段,但只是爲了說清楚,這裏是我想要做的基本輪廓:
- 我有一個包含
DataSet
具有值的DataTable
。對於這個例子,有兩列。ID
可能是任何Integer
,'Selected'可能是任何Boolean
的值。這些都不會是Nothing
或DBNull
。 - 我想將每一行綁定到一個
Checkbox
控件。一個CheckBox
每ID
值。Checked
屬性應該綁定到DataTable
中的Selected
列。 - 進行更改時,用戶點擊
Button
,我希望能夠告訴什麼樣的變化做出的用戶,使用DataSet
(即2行更新的HasChanges()
和GetChanges()
方法,如果用戶已經改變了Checked
財產Checkbox
控件中的兩個控件)。
EDIT 2
感謝@RezaAghaei我想出了一個解決方案。我從我的問題示例中提煉出了代碼,並根據數據生成了所有控件(並相應地定位它們),以使此示例可以簡單地複製和粘貼。此外,這在DataView
上使用RowFilter
,而不是BindingSource
的Position
財產。
Option Strict On
Option Explicit On
Public Class Form1
Public ds As DataSet
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ds = New DataSet()
Dim dt As New DataTable()
dt.Columns.Add("ID", GetType(Integer))
dt.Columns.Add("Selected", GetType(Boolean))
dt.Rows.Add(1, False)
dt.Rows.Add(2, False)
dt.Rows.Add(3, False)
dt.TableName = "Table1"
ds.Tables.Add(dt)
ds.AcceptChanges()
AddHandler dt.ColumnChanged, Sub(sender2 As Object, e2 As DataColumnChangeEventArgs)
e2.Row.EndEdit()
End Sub
For i As Integer = 0 To dt.Rows.Count-1
Dim cb As New CheckBox() With {.Text = "CheckBox" & i+1, .Location = New Point(10, 25 * (i))}
Dim dv As New DataView(dt)
dv.RowFilter = "ID=" & DirectCast(dt.Rows(i)(0), Integer)
Dim bs As New BindingSource(dv, Nothing)
Dim db As New Binding("Checked", bs, "Selected")
db.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged
cb.DataBindings.Add(db)
Me.Controls.Add(cb)
Next
Dim btn As New Button()
btn.Location = New Point(10, 30 * dt.Rows.Count)
btn.Text = "Submit"
AddHandler btn.Click, AddressOf Button1_Click
Me.Controls.Add(btn)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs)
'Me.BindingContext(ds.Tables("Table1")).EndCurrentEdit() 'Doesn't cut the mustard!
If ds.HasChanges()
MessageBox.Show("Number of rows changed: " & ds.GetChanges().Tables("Table1").Rows.Count)
ds.AcceptChanges()
Else
MessageBox.Show("Number of rows changed: 0")
End If
End Sub
End Class
的關鍵是在ColumnChanged
事件調用EndEdit()
爲DataTable
(以EndCurrentEdit()
一般號召只是似乎沒有削減它),但是我遇到了一個額外的問題是,該代碼將無法正常工作如果它的格式爲New()
方法,即使它是在撥打InitializeComponent()
之後。我猜這是因爲Winforms在調用New()
之後做了一些初始化操作,這是數據綁定正常工作所必需的。
我希望這個例子能夠節省其他人花時間研究這個問題的時間。
@RezaAghaei我曾希望這是很清楚的了,但我已經添加了一個額外的對更多clari的第二段判決TY。編輯:你不斷更新你的評論!什麼網格?這裏沒有網格控件。 – Interminable
@RezaAghaei這是一個我正在經歷的行爲的簡單功能示例。該按鈕調用'EndCurrentEdit()'。在一個更大的項目中,這將隨後處理用戶輸入的數據。我在這裏沒有對數據做任何事情,因爲它是無意義的測試數據。我沒有在網格中顯示控件,因爲...爲什麼我需要在網格中顯示它們? – Interminable
@RezaAghaei實際上,控件是動態生成的,但與示例問題的示例無關。上面的代碼旨在成爲[最小,完整和可驗證示例](http://stackoverflow.com/help/mcve)。而已。 – Interminable