[英]DispatcherObject cast woes and Async / ObservableCollection issues in WPF
下面的代码从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)继承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
据我所知,您有两个问题。
您正在将局部变量eventHandler
分配给匿名方法,而不是实际的事件处理程序。 它应该是:
Dim eventHandler As NotifyCollectionChangedEventHandler = CollectionChangedEvent
注意:您需要在VB中使用CollectionChangedEvent
,而不是CollectionChanged
。
您正在使用CType
到目标转换为DispatcherObject
,如果目标不是将不起作用DispatcherObject
。 改用TryCast
:
Dim dispatcherObject As DispatcherObject = TryCast(handler.Target, DispatcherObject)
您还可以使用IsNot
整理下一行的测试:
If dispatcherObject IsNot Nothing AndAlso Not dispatcherObject.CheckAccess Then
警告-以下代码的行为与C#版本不同。 关键的区别似乎是,在VB中,您不能重写事件(为什么不是呢?),而在C#中,您可以重写。
结果是Handler在VB中什么都没有,但在C#中却没有:(。
因此,语法的构建没有错误,但是VB版本从来没有做任何事情。
在VB中重做更新的答案。 谢谢!
注意我还不能使用实体框架。 但是我认为这是我和EF的问题,而不是收藏。
该代码本身适用于任何有兴趣的人。 我的列表现在填充得很好。 但是,我会用一小撮盐来回答我的问题,直到我更新说我如何进行了广泛测试:)
但是,预兆很好-这是原始C#作者的网站: 原始网站
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
末级
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.