[英]DispatcherObject cast woes and Async / ObservableCollection issues in WPF
The code below pulls out a bunch of records from an Access 2010 database; 下面的代码从Access 2010数据库中拉出一堆记录。 hence rolling my own connector bits.
因此滚动我自己的连接器位。 I've succeeded in doing the observablecollection and made it all bind up with nice drag and drop data sources, from my own objects.
我已经成功地进行了observablecollection,并通过我自己的对象中的漂亮的拖放数据源将其绑定在一起。 However, like a daft person, I want to do this Asynchronously.
但是,我想像一个愚蠢的人那样异步地执行此操作。 Yet, I've got a small cast monster problem, and I don't know what to feed it!
但是,我遇到了一个小型怪物问题,而且我不知道该怎么喂! Can anyone advise me - I've tried a lot of reading around, but the concepts are just a little too many at once on a Friday afternoon and I'm struggling to make any real headway.
谁能告诉我-我已经尝试了很多阅读,但是每个星期五一次一次的概念太多了,我正在努力取得任何进展。
The line I'm having trouble with is: Dim dispatcherObject As DispatcherObject = CType (handler.Target, DispatcherObject )
我遇到的问题是:
Dim dispatcherObject As DispatcherObject = CType (handler.Target, DispatcherObject )
The exception is: Unable to cast object of type '_Closure$__2[SomeRecord_Viewer.SomeRecord]' to type 'System.Windows.Threading.DispatcherObject'.
例外是:
Unable to cast object of type '_Closure$__2[SomeRecord_Viewer.SomeRecord]' to type 'System.Windows.Threading.DispatcherObject'.
I've managed to make a WPF listbox populate via the code below, however only by commenting out a part of the ObservableCollectionEx class. 我设法通过下面的代码填充了WPF列表框,但是只能注释掉ObservableCollectionEx类的一部分。 This causes synchronisation problems and a crash after a few hundred records are entered.
输入数百条记录后,这将导致同步问题和崩溃。
Class that builds the threaded list of entities - in this case, an ObservableCollectionEx(Of SomeRecord): 用于构建实体的线程列表的类-在这种情况下,为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`
Partial code for the SomeRecord class: 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
The threaded collection class code - translated from another online source. 线程集合类代码-从另一个在线来源翻译而来。
'I use PostSharp for try catch stuff. ``我使用PostSharp尝试捕捉东西。 ` Public Class ObservableCollectionEx (Of T ) Inherits ObservableCollection( Of T) ' Override the event so this class can access it Public Shadows Event CollectionChanged As System.Collections.Specialized.NotifyCollectionChangedEventHandler
`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
From what I can see, you have two problems. 据我所知,您有两个问题。
You're assigning the local variable eventHandler
to an anonymous method, rather than the actual event handler. 您正在将局部变量
eventHandler
分配给匿名方法,而不是实际的事件处理程序。 It should be: 它应该是:
Dim eventHandler As NotifyCollectionChangedEventHandler = CollectionChangedEvent
NB: You need to use CollectionChangedEvent
in VB, not CollectionChanged
. 注意:您需要在VB中使用
CollectionChangedEvent
,而不是CollectionChanged
。
You're using CType
to cast the target to a DispatcherObject
, which won't work if the target isn't a DispatcherObject
. 您正在使用
CType
到目标转换为DispatcherObject
,如果目标不是将不起作用DispatcherObject
。 Use TryCast
instead: 改用
TryCast
:
Dim dispatcherObject As DispatcherObject = TryCast(handler.Target, DispatcherObject)
You can also tidy up the test on the next line by using IsNot
: 您还可以使用
IsNot
整理下一行的测试:
If dispatcherObject IsNot Nothing AndAlso Not dispatcherObject.CheckAccess Then
WARNING - The code below acts differently to the C# version. 警告-以下代码的行为与C#版本不同。 The key difference seems to be that in VB you can't Override an Event (Why on earth not?) yet in C# you can.
关键的区别似乎是,在VB中,您不能重写事件(为什么不是呢?),而在C#中,您可以重写。
The result is the Handler is Nothing in VB but not in C# :(. 结果是Handler在VB中什么都没有,但在C#中却没有:(。
So the syntax builds without error but the VB version doesn't ever do anything. 因此,语法的构建没有错误,但是VB版本从来没有做任何事情。
Redone with the updated answer in VB. 在VB中重做更新的答案。 Thank you!
谢谢!
Note I cannot make this work with Entity Framework, yet. 注意我还不能使用实体框架。 But I think that a me and EF issue, not the collection.
但是我认为这是我和EF的问题,而不是收藏。
The code itself is here for anyone interested. 该代码本身适用于任何有兴趣的人。 My list DOES populate perfectly fine now.
我的列表现在填充得很好。 However, I would take this answer of mine with a small pinch of salt until I update saying how I've extensively tested perhaps :)
但是,我会用一小撮盐来回答我的问题,直到我更新说我如何进行了广泛测试:)
However the omens are good - here is the original C# author's site: Original Site 但是,预兆很好-这是原始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
End Class 末级
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.