0

下面的代码从 Access 2010 数据库中提取了一堆记录;因此滚动我自己的连接器位。我已经成功地完成了 observablecollection 并通过我自己的对象的漂亮拖放数据源将其全部绑定在一起。但是,像一个愚蠢的人一样,我想异步执行此操作。然而,我有一个小怪物问题,我不知道该喂它什么!谁能给我建议-我已经尝试了很多阅读,但是在星期五下午,这些概念一次太多了,我正在努力取得任何真正的进展。

我遇到的问题是: Dim dispatcherObject As DispatcherObject = CType (handler.Target, DispatcherObject )

例外是: Unable to cast object of type '_Closure$__2[SomeRecord_Viewer.SomeRecord]' to type 'System.Windows.Threading.DispatcherObject'.

我已经设法通过下面的代码填充了 WPF 列表框,但是只能通过注释掉 ObservableCollectionEx 类的一部分。这会导致同步问题并在输入数百条记录后崩溃。

构建实体的线程列表的类 - 在本例中为 ObservableCollectionEx(Of SomeRecord):

Class SomeRecordSet
Inherits ObservableCollectionEx( Of  SomeRecord)

Private Shared Property _SomeRecordList As New ObservableCollectionEx(Of  SomeRecord )
Public Shared ReadOnly Property SomeRecordList As ObservableCollectionEx(Of  SomeRecord )
    Get
        If _SomeRecordList.Count = 0 Then BuildSomeRecordListAsync()
        Return _SomeRecordList
    End Get
End Property

Public Shared ReadOnly Property ReturnSingleSomeRecord(id As Integer) As SomeRecord
    Get
        Return ( From SomeRecord In _SomeRecordList Where SomeRecord.id = id Select        SomeRecord).First()
    End Get
End Property

Private Shared Async Sub BuildSomeRecordListAsync()
    Await Task.Run( Sub() BuildSomeRecordList())
    Return
End Sub

Private Shared Sub BuildSomeRecordList()
    Db.newcmd( "Select * from  RecordList ")
    While Db.read
        Dim SomeRecord As New SomeRecord
        With SomeRecord
            .id = Db.dbint( "ID")
            .type = Db.dbin( "type")
         End With
        _SomeRecordList.Add(SomeRecord)
    End While
End Sub`

SomeRecord 类的部分代码:

Class SomeRecord
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements                   INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged( ByVal info As String)
    RaiseEvent PropertyChanged(Me , New PropertyChangedEventArgs (info))
End Sub

...'lots of simple properties.
End Class

线程集合类代码 - 翻译自另一个在线资源。

'我使用 PostSharp 来尝试捕捉东西。` Public Class ObservableCollectionEx (Of T) Inherits ObservableCollection(Of T) ' 覆盖事件,以便此类可以访问它 Public Shadows Event CollectionChanged As System.Collections.Specialized.NotifyCollectionChangedEventHandler

Protected Overrides Sub OnCollectionChanged( ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs )

    Using BlockReentrancy()

        Dim eventHandler As System.Collections.Specialized.NotifyCollectionChangedEventHandler = Sub () RaiseEvent CollectionChanged(Me , e)
        If (eventHandler Is Nothing) Then Return

        Dim delegates() As [Delegate] = eventHandler.GetInvocationList
*******If I comment this out I can populate the Listbox via a CollectionView, however it dies with issues to do with the list not staying synchronised :).
        'Walk thru invocation list 
        For Each handler As System.Collections.Specialized.NotifyCollectionChangedEventHandler     In delegates
            Dim dispatcherObject As DispatcherObject = CType (handler.Target, DispatcherObject)
            ' If the subscriber is a DispatcherObject and different thread
            If (( Not (dispatcherObject) Is Nothing) AndAlso (dispatcherObject.CheckAccess = False )) Then
                ' Invoke handler in the target dispatcher's thread
                dispatcherObject.Dispatcher.Invoke(DispatcherPriority .DataBind, handler, Me, e)
            Else
                handler( Me, e)
            End If
        Next

*******End of stuff I comment out to get working partially***

    End Using
End Sub
End Class
4

2 回答 2

1

据我所知,你有两个问题。

  1. 您将局部变量分配给eventHandler匿名方法,而不是实际的事件处理程序。它应该是:

    Dim eventHandler As NotifyCollectionChangedEventHandler = CollectionChangedEvent
    

    注意:您需要CollectionChangedEvent在 VB 中使用,而不是CollectionChanged.

  2. CType用于将目标强制转换为 a DispatcherObject,如果目标不是 a ,这将不起作用DispatcherObject。改用TryCast

    Dim dispatcherObject As DispatcherObject = TryCast(handler.Target, DispatcherObject)
    

您还可以使用以下命令整理下一行的测试IsNot

If dispatcherObject IsNot Nothing AndAlso Not dispatcherObject.CheckAccess Then
于 2013-01-11T19:41:14.730 回答
0

警告 - 下面的代码与 C# 版本的行为不同。关键的区别似乎在于,在 VB 中你不能覆盖事件(为什么不呢?)但在 C# 中你可以。

结果是 Handler 在 VB 中是 Nothing 但在 C# 中不是 :(。

所以语法构建没有错误,但 VB 版本没有做任何事情。

用 VB 中的更新答案重做。谢谢!

请注意,我还不能使用 Entity Framework 进行这项工作。但我认为这是我和 EF 的问题,而不是集合。

代码本身在这里供任何感兴趣的人使用。我的列表现在确实填充得很好。但是,我会用一小撮盐来回答我的这个答案,直到我更新说我可能已经广泛测试了:)

然而,预兆是好的 - 这是原始 C# 作者的站点:Original Site

Public Class ObservableCollectionEx(Of T)
Inherits ObservableCollection(Of T)



'Override the event so this class can access it
Public Shadows Event CollectionChanged As NotifyCollectionChangedEventHandler

Protected Overrides Sub OnCollectionChanged(ByVal e As NotifyCollectionChangedEventArgs)
    Using BlockReentrancy()
        Dim eventHandler As System.Collections.Specialized.NotifyCollectionChangedEventHandler = CollectionChangedEvent
        If eventHandler Is Nothing Then
            Return
        End If


        Dim delegates() As [Delegate] = CollectionChangedEvent.GetInvocationList
        'Walk thru invocation list
        For Each handler As NotifyCollectionChangedEventHandler In delegates
            Dim dispatcherObject As DispatcherObject = TryCast(handler.Target, DispatcherObject)
            ' If the subscriber is a DispatcherObject and different thread
            If dispatcherObject IsNot Nothing AndAlso Not dispatcherObject.CheckAccess Then
                ' Invoke handler in the target dispatcher's thread
                dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, Me, e)
            Else
                handler(Me, e)
            End If
        Next
    End Using
End Sub

结束类

于 2013-01-12T20:40:25.753 回答