从不同线程 vb.net 更新 BindingList(of T)
Update BindingList(of T) from different thread vb.net
几天前我一直在寻找来自其他线程的 BindingList Invoke,但无法在 vb.net 中找到合适的解决方案,其中大部分是在 C# 中,但我发现很难理解。
因此,我创建了一个小型应用程序,它有 2 个表单(Form1 和 Form2)和一个 Class,Form1 将是主 UI 线程,而 Form2 将是 运行 在另一个线程上。
Form1 有一个 DataGrindView 绑定到共享的 BindingList(of T) 和一个 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 class 实例,更改它的一个 属性 并尝试添加到 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 代码
引起问题的是 DataGridView 的更新。
从你的评论我可以看出是因为DataGridView绑定到DataGridView的DataSource,所以如果你在一个单独的线程上更新这个List会导致跨线程操作。
一个解决方案是不创建 ListOfNames
public 并使用新方法允许添加到此列表:
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
最后,在大家的建议和下面的测试之后,对 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
几天前我一直在寻找来自其他线程的 BindingList Invoke,但无法在 vb.net 中找到合适的解决方案,其中大部分是在 C# 中,但我发现很难理解。 因此,我创建了一个小型应用程序,它有 2 个表单(Form1 和 Form2)和一个 Class,Form1 将是主 UI 线程,而 Form2 将是 运行 在另一个线程上。
Form1 有一个 DataGrindView 绑定到共享的 BindingList(of T) 和一个 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 class 实例,更改它的一个 属性 并尝试添加到 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 代码
引起问题的是 DataGridView 的更新。
从你的评论我可以看出是因为DataGridView绑定到DataGridView的DataSource,所以如果你在一个单独的线程上更新这个List会导致跨线程操作。
一个解决方案是不创建 ListOfNames
public 并使用新方法允许添加到此列表:
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
最后,在大家的建议和下面的测试之后,对 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