从ViewModel中的Observable集合中删除不会更新View,但现有项目的更新会更新View

时间:2013-09-02 19:15:25

标签: .net wpf mvvm viewmodel observablecollection

我相信这对某人来说是一个扣篮...... 手指交叉

我的ListView ItemsSource绑定到我的ViewModel上名为TileItems的Property。

完美填充列表视图更新。

在ViewModel中,您可以看到“existingTileItem.Transaction = e.Transaction”。 。 。单个列表视图项目完美更新。

在ViewModel中,您可以看到“Me.TileItems.Remove(existingTileItem)”...项目未从视图中删除。它确实从Me.TileItems集合中成功删除,但视图中未描述更新。

附加信息:AbstractViewModel实现了INotificationPropertyChanged,我尝试在TileItem中覆盖Equals而不是覆盖它,并且所有周围都会发生相同的结果。我看到了this回答和this回答,但他们没有回答我遇到的问题。

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" />

视图模型:

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模型:

Public Class TileItems
    Inherits ObservableCollection(Of TileItem)

End Class

TileItem模型:

 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

更新

根据@ReedCopsey的回答,这是我为实现这一目标所做的更新。

我将Me.TileItems.Remove(existingTileItem)更新为现在

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

1 个答案:

答案 0 :(得分:7)

从我所看到的,您正在粘贴的代码应该可以正常工作。最可能的罪魁祸首是您的TransactionUpdateReceived事件是在不是用户界面线程的线程上引发的。在WPF中,可以在后台线程上修改单个项目,但是集合不能(在.NET 4.5之前,但在.NET 4.5中,它们需要额外的工作)。

有两种选择。如果您使用的是.NET 4.5,则可以使用BindingOperations.EnableCollectionSynchronization来允许从后台线程修改ObservableCollection

或者,您可以使用Dispatcher.Invoke将添加/删除调用推送到主线程。