2

我有一个ObservableCollection使用FileSystemWatcher自动添加已添加到目录中的其他PNG图像。 ListBox使用以下XAML将ItemsSource数据绑定到Photos对象。ObservableCollection FileSystemWatcher列表框更新问题

<ListBox ItemsSource="{Binding Source={StaticResource Photos}}" IsSynchronizedWithCurrentItem="True"/> 

然而,当一个PNG文件添加到被监视的目录被称为OnPhotoCreated事件(断点证实了这一点),但是列表框UI没有被更新。有任何想法吗?

Public Class Photos 
Inherits Collections.ObjectModel.ObservableCollection(Of BitmapImage) 

' Events 
Public Event ItemsUpdated As EventHandler 

' Fields 
Private FileSystemWatchers As Dictionary(Of String, FileSystemWatcher) = New Dictionary(Of String, FileSystemWatcher) 

' Methods 
Protected Overrides Sub ClearItems() 
    MyBase.ClearItems() 
    Me.FileSystemWatchers.Clear() 
End Sub 

Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As BitmapImage) 
    MyBase.InsertItem(index, item) 
    Dim ImagePath As String = IO.Path.GetDirectoryName(item.UriSource.LocalPath) 
    If Not Me.FileSystemWatchers.ContainsKey(ImagePath) Then 
     Dim FileWatcher As New FileSystemWatcher(ImagePath, "*.png") 
     FileWatcher.EnableRaisingEvents = True 
     AddHandler FileWatcher.Created, New FileSystemEventHandler(AddressOf Me.OnPhotoCreated) 
     AddHandler FileWatcher.Deleted, New FileSystemEventHandler(AddressOf Me.OnPhotoDeleted) 
     AddHandler FileWatcher.Renamed, New RenamedEventHandler(AddressOf Me.OnPhotoRenamed) 
     Me.FileSystemWatchers.Add(ImagePath, FileWatcher) 
    End If 
End Sub 

Private Sub OnPhotoCreated(ByVal sender As Object, ByVal e As FileSystemEventArgs) 
    MyBase.Items.Add(New BitmapImage(New Uri(e.FullPath))) 
    RaiseEvent ItemsUpdated(Me, New EventArgs) 
End Sub 

Private Sub OnPhotoDeleted(ByVal sender As Object, ByVal e As FileSystemEventArgs) 
    Dim index As Integer = -1 
    Dim i As Integer 
    For i = 0 To MyBase.Items.Count - 1 
     If (MyBase.Items.Item(i).UriSource.AbsolutePath = e.FullPath) Then 
      index = i 
      Exit For 
     End If 
    Next i 
    If (index >= 0) Then 
     MyBase.Items.RemoveAt(index) 
    End If 
    RaiseEvent ItemsUpdated(Me, New EventArgs) 
End Sub 

Private Sub OnPhotoRenamed(ByVal sender As Object, ByVal e As RenamedEventArgs) 
    Dim index As Integer = -1 
    Dim i As Integer 
    For i = 0 To MyBase.Items.Count - 1 
     If (MyBase.Items.Item(i).UriSource.AbsolutePath = e.OldFullPath) Then 
      index = i 
      Exit For 
     End If 
    Next i 
    If (index >= 0) Then 
     MyBase.Items.Item(index) = New BitmapImage(New Uri(e.FullPath)) 
    End If 
    RaiseEvent ItemsUpdated(Me, New EventArgs) 
End Sub 


End Class 

更新#1:我试图事件,如下图所示。这会导致InvalidOperationException崩溃,“调用线程无法访问此对象,因为不同的线程拥有它”当新图像尝试滚动到视图中时。我希望Refresh方法不需要。

Dim Photos As Photos = CType(Me.FindResource("Photos"), Photos) 
AddHandler Photos.ItemsUpdated, AddressOf Me.Photos_ItemsUpdated 

Private Sub RefreshPhotos() 
    ' 
    If Me.ImageListBox.Dispatcher.CheckAccess = True Then 
     Me.ImageListBox.Items.Refresh() 
    Else 
     Dispatcher.BeginInvoke(DispatcherPriority.Normal, New DispatcherMethodCallback(AddressOf Me.RefreshPhotos)) 
    End If 
    ' 
End Sub 

Private Sub Photos_ItemsUpdated(ByVal sender As Object, ByVal e As EventArgs) 
    ' 
    Debug.WriteLine("PhotosUpdated") 
    Me.RefreshPhotos() 
    ' 
End Sub 
+0

我看到一堆对RaiseEvent ItemsUpdated的调用,但是我没有看到您正在处理该事件。我错过了什么吗? – David 2009-08-01 04:00:54

回答

1

看看从类的ObservableCollection(从反射镜)的InsertItem代码:

Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As T) 
    Me.CheckReentrancy 
    MyBase.InsertItem(index, item) 
    Me.OnPropertyChanged("Count") 
    Me.OnPropertyChanged("Item[]") 
    Me.OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index) 
End Sub 

现在使用作为一个准则是什么通知的的ObservableCollection应该执行。 OnCollectionChanged方法是wpf通知系统的主要连接,如果它被适当调用,那么这个calss工作正常,而其他地方就是这个问题。

而且,在你的OnPhotoCreated方法,调用Items.Add方法,其中不做通知,它不属于的ObservableCollection类,但Collection<T>类从中继承的ObservableCollection。

至于InvalidOperationException错误,听起来像是从错误的线程更新到我的UI的情况。