所以我一直在浏览,有很多关于如何将数据从列表框移动到列表框的解释。
我有一个列表框绑定到我的SQL服务器的源和另一个未绑定的源。我的目标是将数据从第一个(LBsearch)
移动到第二个(LBselect)
并返回。我见过有人说用过
LBselect.Items.Add(LBsearch.SelectedItem)
但它不返回数据,而是显示System.Data.DataRowView
。我尝试过很多不同的后缀,并且除了LBsearch.text
之外都显示了这一点。然后从第一个删除数据我已经删除了数据绑定源(PersonBindingSource)
PersonBindingSource.Remove(LBsearch.SelectedItem)
但我的问题是再次添加数据。
PersonBindingSource.Add(LBselect.SelectedItem)
会出错:
System.InvalidOperationException: Objects added to a BindingSource's list must all be of the same type.
at System.Windows.Forms.BindingSource.Add(Object value)
at Project_Program.Participants.btnremoveselect_Click(Object sender, EventArgs e) in E:\Documents\Visual Studio\Project Program\Project Program\Participants.vb:line 39
PersonBindingSource.Add(PersonBindingSource.Item(LBsearch.SelectedIndex))
给出错误:
System.ArgumentException: Cannot add external objects to this list.
at System.Data.DataView.System.Collections.IList.Add(Object value)
at System.Windows.Forms.BindingSource.Add(Object value)
at Project_Program.Participants.btnremoveselect_Click(Object sender, EventArgs e) in E:\Documents\Visual Studio\Project Program\Project Program\Participants.vb:line 38
任何帮助将不胜感激。感谢
Private Sub btnaddselect_Click(sender As Object, e As EventArgs) Handles btnaddselect.Click
If LBsearch.Items.Count > 0 Then
MsgBox(LBsearch.Text)
' PersonBindingSource.Remove(PersonBindingSource.Item(LBsearch.SelectedIndex))
LBselect.Items.Add(LBsearch.Text)
PersonBindingSource.Remove(LBsearch.SelectedItem)
' filter()
End If
End Sub
Private Sub btnremoveselect_Click(sender As Object, e As EventArgs) Handles btnremoveselect.Click
If LBselect.Items.Count > 0 Then
Try
'PersonBindingSource.Add(PersonBindingSource.Item(LBsearch.SelectedIndex))
PersonBindingSource.Add(LBselect.SelectedItem)
MsgBox(LBselect.SelectedItem.ToString())
LBselect.Items.Remove(LBselect.SelectedItem)
Catch ex As Exception
TextBox1.Text = (ex.ToString)
End Try
'filter()
End If
End Sub
答案 0 :(得分:1)
移动行的一个主要问题是,因为它们是DataRow
,所以它们在未绑定的控件中不会很好地显示。如果你拿出像名字一样有用的东西,你将不得不重新创建DataRow
以将其返回到原始/绑定/源控件。
这是一个问题,因为现在它是新行,因此DataAdpter可能会再次将其添加到数据库中!避免这种情况的一种方法是克隆表。此外,如果/当您将它们移回时,它们将显示在列表的底部而不是原始位置。
有一种比复制表数据和移动任何地方更好的方法。
由于被选中的行为可以用简单的布尔表示,因此可以对其进行编码,使Selected
个显示在一个控件中,未选择的显示在另一个控件中。为此,需要新的Selected
列。如果可能,使用SQL添加一个:
' MS Access syntax
Dim SQL = "SELECT a, b, c,..., False As Selected FROM tblFoo"
这将在数据表中创建新列,其中所有值都初始化为False
。您也可以手动添加列。
' form level vars
Private dvSource As DataView
Private dvDest As DataView
...
' set up:
' *** Add a column manually if you cant use SQL
dtSample.Columns.Add("Selected", GetType(Boolean))
' we need to loop and set the initial value for an added column
For Each r As DataRow In dtSample.Rows
r("Selected") = False
Next
' *** end of code for adding col manually
' when the column is added from SQL, you will need:
dtSample.Columns("Selected").ReadOnly = False
' create Source DV as Selected = False
dvSource = New DataView(dtSample,"Selected=False", "",
DataViewRowState.CurrentRows)
' create Dest DV as Selected = True
dvDest = New DataView(dtSample, "Selected=True", "",
DataViewRowState.CurrentRows)
' assign DS
lbSource.DataSource = dvSource
lbSource.DisplayMember = "Name"
lbSource.ValueMember = "Id"
lbDest.DataSource = dvDest
lbDest.DisplayMember = "Name"
lbDest.ValueMember = "Id"
然后在点击事件中:
' select
CType(lbSource.SelectedItem, DataRowView).Row("Selected") = True
' deselect:
CType(lbSource.SelectedItem, DataRowView).Row("Selected") = False
两个DataView
对象将在Selected
上反向过滤。当您更改行的状态时,它会立即从一个行中删除并显示在另一个中,而不会实际添加/删除任何表(或集合或控件)。如果将其移回源,它将显示在与之前相同的位置。
在这种情况下,移动的任何项目的RowState
将是Modified
,当然这是(与移动到桌面的方法不同,它们是新行(Added
})他们不是。)
没有5或6张图片很难说明,但想法是:
这实际上是一种非常简单的方法,比一次实际移动行更经济。使用DataView
s行/项看起来像它们移动到另一个表或控件,但它们没有,也不需要。