【问题标题】:Update BindingList(of T) from different thread vb.net从不同的线程 vb.net 更新 BindingList(of T)
【发布时间】:2016-07-15 14:03:43
【问题描述】:

几天前我一直在从其他线程中寻找 BindingList Invoke,但无法在 vb.net 中获得适当的解决方案,其中大部分都在 C# 中,但我发现很难理解。 因此我创建了一个小应用程序,它有 2 个表单(Form1 和 Form2)和一个类,Form1 将是主 UI 线程,而 Form2 将在不同的线程上运行。

Form1 有一个绑定到共享 BindingList(of T) 的 DataGrindView 和一个 Button,一旦单击 Button,Form2 将被加载到不同的线程上。

这是 Form1 代码:

Imports System.ComponentModel
Imports System.Threading
Public Class Form1
    Public Shared ListOfNames As BindingList(Of Names) = New BindingList(Of Names)

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        DataGridView1.DataSource = ListOfNames
        DataGridView1.Columns("FullName").DataPropertyName = "FullName"
    End Sub

    Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
        Dim thread As Threading.Thread = New Threading.Thread(AddressOf loadQuoteForm)
        thread.SetApartmentState((ApartmentState.STA))
        thread.Start()
    End Sub

    Private Sub loadQuoteForm()
        Dim SecondForm As Form2 = New Form2
        Application.Run(SecondForm)
    End Sub
End Class

Form2 只有一个按钮,点击后会创建一个 Names 类实例,更改它的一个属性并尝试添加到 Form1.BindingList(of T)。

这是 Form2 代码:

Public Class Form2
    Private Sub btnTestFromDiffTread_Click(sender As Object, e As EventArgs) Handles btnTestFromDiffTread.Click
        Try
            Dim myName As Names = New Names
            myName.FullName = "John Peter"
            Form1.ListOfNames.Add(myName)
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Sub
End Class


Imports System.ComponentModel
Public Class Names
    Implements System.ComponentModel.INotifyPropertyChanged
    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    Private _fullName As String
    Public Property FullName() As String
        Get
            Return _fullName
        End Get
        Set(ByVal value As String)
            _fullName = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("FullName"))
        End Set
    End Property
End Class

但正如您可能已经猜到的那样,只要单击 Form2 上的按钮就会引发异常: .

任何人都可以建议我应该在哪里调用或委托,非常感谢示例 VB.net 代码

【问题讨论】:

    标签: c# vb.net multithreading bindinglist


    【解决方案1】:

    导致问题的原因是 DataGridView 的更新。

    从您的评论中我可以看出这是因为 DataGridView 绑定到 DataGridView 的 DataSource,因此如果您在单独的线程上执行此操作,则更新此 List 将导致跨线程操作。

    一种解决方案是不公开ListOfNames,并有一种新方法允许添加到此列表中:

    Private Shared ListOfNames As BindingList(Of Names) = New BindingList(Of Names)
    
    Public Sub AddNameToList(newNames As Names)
        DataGridView1.BeginInvoke(Sub() ListOfNames.Add(newNames))
    End Sub
    

    【讨论】:

    • 不,在执行建议的修复后仍然显示错误:-“System.InvalidOperationException:跨线程操作无效:控制'DataGridView1'从创建它的线程以外的线程访问。”
    • 不,错误出现在 Form2 行:7,即“Form1.ListOfNames.Add(myName)”。 ListOfNames 是 DataGridView1 的数据源
    • 顺便说一句,非常感谢您的快速更新!,看起来它正在进步,我已经按照您的建议进行了更改,现在错误消息有所不同,但在表格 2 的第 7 行,错误消息是:System.InvalidOperationException:在创建窗口句柄之前无法在控件上调用 Invoke 或 BeginInvoke”
    • 对不起,当我们创建一个方法来执行调用时,它已经被删除了,上面所说的错误是在 FormLoad 上存在 BeginInvoke 以及什么时候不存在时抛出
    【解决方案2】:

    最后,在大家的建议和测试之后,Form2 按钮点击的更改以及在 Form1 上添加一些方法解决了这个问题:

    在 Form1 上添加了那里的方法

    Private Shared ListOfNames As BindingList(Of Names) = New BindingList(Of Names)
    Private Delegate Sub AddNameToListDelegate(newName As Names)
    
    Public Sub InvokeANDCreateHandle(ByVal newNames As Names)
        Try
            If Me.IsHandleCreated = False Then
                Me.CreateHandle()
            End If
            DataGridView1.Invoke(New AddNameToListDelegate(AddressOf AddNameToList), newNames)
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Sub
    
    Private Sub AddNameToList(name As Names)
        ListOfNames.Add(name)
    End Sub
    

    并将From2上的按钮更改为:

     Private Sub btnTestFromDiffTread_Click(sender As Object, e As EventArgs) Handles btnTestFromDiffTread.Click
        Try
            Dim myName As Names = New Names
            myName.FullName = "John Peter"
            Form1.InvokeANDCreateHandle(myName)
        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
     End Sub
    

    【讨论】:

      猜你喜欢
      • 2014-08-11
      • 2010-10-02
      • 1970-01-01
      • 2013-03-02
      • 1970-01-01
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      相关资源
      最近更新 更多