簡體   English   中英

WPF中DispatcherObject的問題和Async / ObservableCollection問題

[英]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

據我所知,您有兩個問題。

  1. 您正在將局部變量eventHandler分配給匿名方法,而不是實際的事件處理程序。 它應該是:

     Dim eventHandler As NotifyCollectionChangedEventHandler = CollectionChangedEvent 

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

  2. 您正在使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM