4

I'm sure this will be a slam dunk for someone... fingers crossed

My ListView ItemsSource is bound to a Property on my ViewModel named TileItems.

Populating the list view updates perfectly.

In the ViewModel, where you see "existingTileItem.Transaction = e.Transaction" . . . The individual listview item updates perfectly.

In the ViewModel, where you see "Me.TileItems.Remove(existingTileItem)" ... The item is not removed from the View. It does successfully remove from the Me.TileItems collection, but the update is not depicted in the View.

Additional Info: AbstractViewModel implements INotificationPropertyChanged, I've tried overriding Equals in the TileItem and not overriding it, and the same results all around happen. I have seen this answer and this answer, but they do not answer the issue I am having.

XAML:

<UserControl.DataContext>
    <local:TransactionTileResultsViewControlViewModel />
</UserControl.DataContext>

<ListView Grid.Row="1"  Name="tileItems" ItemsSource="{Binding TileItems, Mode=TwoWay}" 
                  ItemTemplate="{StaticResource tileItemDataTemplate}" ScrollViewer.HorizontalScrollBarVisibility="Hidden"
                  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />

ViewModel:

Public Class TransactionTileResultsViewControlViewModel
    Inherits AbstractViewModel
    Implements INavigationAware

    Private _tileItems As TileItems
    Public Property TileItems As TileItems
        Get
            Return Me._tileItems
        End Get
        Set(value As TileItems)
            Me._tileItems = value
            MyBase.RaisePropertyChanged("TileItems")
        End Set
    End Property

'....


    #Region "TransactionUpdateReceived Methods"

        Private Sub TransactionUpdateReceived_Handler(ByVal e As TransactionUpdatedEvent)

            If e.Transaction IsNot Nothing Then

                Dim existingTileItem As TileItem = Me.TileItems.Where(Function(t) t.Transaction.TransactionQueueID = e.Transaction.TransactionQueueID).FirstOrDefault()
                If existingTileItem IsNot Nothing Then

                    If e.Transaction.Canceled Then

                          Me.TileItems.Remove(existingTileItem)

                    Else

                        If e.Transaction.ContainsFailedActivites() OrElse e.Transaction.ContainsCallbackActivities() Then

                            existingTileItem.Transaction = e.Transaction

                        Else

                            Me.TileItems.Remove(existingTileItem)

                        End If

                    End If

                End If

            End If

        End Sub

#End Region

End Class

TileItems Model:

Public Class TileItems
    Inherits ObservableCollection(Of TileItem)

End Class

TileItem Model:

 Imports Microsoft.Practices.Prism.ViewModel

    Public Class TileItem
        Inherits NotificationObject

        Private _created As Date
        Public Property Created As Date
            Get
                Return _created
            End Get
            Set(value As Date)
                _created = value
                MyBase.RaisePropertyChanged("Created")
            End Set
        End Property

        Private _category As String
        Public Property Category As String
            Get
                Return _category
            End Get
            Set(value As String)
                _category = value
                MyBase.RaisePropertyChanged("Category")
            End Set
        End Property

        Private _tileField1 As String
        Public Property TileField1 As String
            Get
                Return _tileField1
            End Get
            Set(value As String)
                _tileField1 = value
                MyBase.RaisePropertyChanged("TileField1")
            End Set
        End Property

        Private _tileField2 As String
        Public Property TileField2 As String
            Get
                Return _tileField2
            End Get
            Set(value As String)
                _tileField2 = value
                MyBase.RaisePropertyChanged("TileField2")
            End Set
        End Property

        Private _tileField3 As String
        Public Property TileField3 As String
            Get
                Return _tileField3
            End Get
            Set(value As String)
                _tileField3 = value
                MyBase.RaisePropertyChanged("TileField3")
            End Set
        End Property

        Private _transaction As Transaction
        Public Property Transaction As Transaction
            Get
                Return _transaction
            End Get
            Set(value As Transaction)
                _transaction = value
                MyBase.RaisePropertyChanged("Transaction")
            End Set
        End Property

    Public Overrides Function Equals(obj As Object) As Boolean

        If TypeOf obj Is TileItem Then

            Dim tileItem As TileItem = DirectCast(obj, TileItem)

            If tileItem.Transaction IsNot Nothing AndAlso Me.Transaction IsNot Nothing Then

                Return tileItem.Transaction.TransactionQueueID = Me.Transaction.TransactionQueueID

            Else
                Return False

            End If

        Else
            Return False
        End If

    End Function


    End Class

UPDATE:

Per @ReedCopsey 's answer, here is the update I made to get this working.

I updated Me.TileItems.Remove(existingTileItem) to be this now

Me.View.Dispatcher.Invoke(Sub()
                              Me.TileItems.Remove(existingTileItem)
                          End Sub, DispatcherPriority.ApplicationIdle)
4

1 に答える 1

7

私が見る限り、貼り付けているコードは機能するはずです。最も可能性の高い原因はTransactionUpdateReceived、ユーザー インターフェイス スレッドではないスレッドでイベントが発生していることです。WPF では、単一のアイテムはバックグラウンド スレッドで変更できますが、コレクションは変更できません (.NET 4.5 より前、.NET 4.5 では追加の作業が必要です)。

2 つのオプションがあります。.NET 4.5 を使用している場合は、バックグラウンド スレッドからの変更BindingOperations.EnableCollectionSynchronizationを許可するために使用できます。ObservableCollection

Dispatcher.Invokeまたは、 Add/Remove 呼び出しをメイン スレッドにプッシュするために使用できます。

于 2013-09-02T19:25:20.760 に答える