将数据从数据绑定列表框移动到未绑定的列表框并返回VB.NET

时间:2016-04-01 13:50:43

标签: vb.net listbox bindingsource

所以我一直在浏览,有很多关于如何将数据从列表框移动到列表框的解释。 我有一个列表框绑定到我的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

1 个答案:

答案 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张图片很难说明,但想法是:

enter image description here

这实际上是一种非常简单的方法,比一次实际移动行更经济。使用DataView s行/项看起来像它们移动到另一个表或控件,但它们没有,也不需要。