2012-02-27 72 views
1

我想直观地显示一个项目(在我的情况下是一个BitmapImage)已被添加到使用WPF/MVVM的ListBox中的集合。为了给出一些背景知识,我使用捕捉卡捕捉流式视频,并且在视频流式传输时拍摄静态图像。这些图像是通过单击UI上的“静止图像”按钮捕获的。捕捉图像后,我想要在UI上的单独面板中显示所述图像的缩略图。我明白需要做些什么才能做到这一点,但我似乎无法使其发挥作用。现在,我的模型执行所有数据检索。更新到ListBox绑定集合后刷新UI

public ObservableCollection<BitmapImage> GetAssetThumbnails() 
{ 
    var imageDir = ImgPath != null ? new DirectoryInfo(ImgPath) : null; 
    if(imageDir != null) 
    { 
     try 
     { 
      foreach (FileInfo imageFile in imageDir.GetFiles("*.jpg")) 
      { 
       var uri = new Uri(imageFile.FullName); 
       _assetThumbnails.Add(new BitmapImage(uri)); 
      } 

     } 
     catch (Exception) 
     { 
      return null; 
     } 
    } 

    return _assetThumbnails; 
} 

我的视图模型建立在其构造模型的新实例,然后设置公共财产等于_assetModel.GetAssetThumbnails()。 ViewModel具有所有标准的OnPropertyChanged事件和事件处理。

private void OnPropertyChanged(string propertyName) 
{ 
    if(PropertyChanged != null) 
    { 
     PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

#region Public Properties 
public ObservableCollection<BitmapImage> AssetCollection 
{ 
    get { return _assetCollection; } 
    set 
    { 
     if (_assetCollection != value) 
     { 
      _assetCollection = value; 
      OnPropertyChanged("AssetCollection");  
     } 
    } 
} 
#endregion 

private void _assetCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
{ 
    OnPropertyChanged("AssetCollection"); 
} 
public event PropertyChangedEventHandler PropertyChanged; 

然后,在我的XAML文件中,我将ListBox的项目源绑定到AssetCollection。

<ListBox x:Name="lstBoxAssets" ItemsSource="{Binding AssetCollection}" Grid.Row="1" Background="{DynamicResource GrayColor}" Margin="5,0,0,5" ></ListBox> 

我读过,集合中的每个项目都应该实现INotifyPropertyChanged接口。我试图创建一个实现该位图图像的包装类,但它也没有工作。有什么我在这里失踪?图像最初显示,但在图像被捕获和保存后不刷新。我有一种感觉,这是来自事件PropertyChanged没有得到调用。我通过调试发现它在检查时始终为空,因此从不调用OnPropetyChanged方法。我不知道我应该在哪里添加这个事件处理程序。我只使用代码隐藏文件将视图模型的数据上下文添加到视图,就是这样。这正是我通常想要添加任何事件处理的地方。任何人都可以看到简单的东西,我在这里失踪?

+0

尝试“我试图创建一个包装类的位图图像实现,但它也没有工作。”再次。对项目的更改需要通过NotifyPropertyChanged从项目中获得。你有没有使用公共财产? – Paparazzi

+0

是的,该物业是公共的。我会尝试再次创建一个包装类。我上次可能错过了一些东西。 – Zajn

回答

2

当您更新列表或更改存储在集合中的项目时,是否更改ObservableCollection

如果您要更改集合中的项目,您需要找到一种方法告诉WPF,当单个项目发生更改时集合已更改,以便知道重绘它。

通常情况下,集合中的项目实施INotifyPropertyChanged,所以很容易为PropertyChange通知连接到物品,告诉WPF提高CollectionChanged事件每当属性更改列表。

// Wireup CollectionChanged in Constructor 
public MyViewModel() 
{ 
    ListOfSomeItems = new List<SomeItem>(); 
    AssetCollection.CollectionChanged += AssetCollection_CollectionChanged; 
} 

// In CollectionChanged event, wire up PropertyChanged event on items 
void AssetCollection_CollectionChanged(object sender, CollectionChangedEventArgs e) 
{ 
    if (e.NewItems != null) 
    { 
     foreach(Asset item in e.NewItems) 
      item.PropertyChanged += Asset_PropertyChanged; 
    } 
    if (e.OldItems != null) 
    { 
     foreach(Asset item in e.OldItems) 
      item.PropertyChanged -= Asset_PropertyChanged; 
    } 
} 

// In PropertyChanged, raise CollectionChanged event 
void Asset_PropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    OnPropertyChanged("AssetCollection"); 
} 

如果项目没有实现INotifyPropertyChanged,你必须手动提升CollectionChanged事件随时随地的项目在收集变化。

AssetCollection[0].Thumbnail = new BitmapImage(uri); 
OnPropertyChanged("AssetCollection"); 

如果您是通过添加/删除项目更改ObservableCollection本身并没有看到UI更新,那么它听起来像它可能是一个语法错误的地方,我们看不到。

我看到的最常见的是对私有财产进行更改,而不是公共财产。

// Will not raise the CollectionChanged notification 
_assetCollection = _assetModel.GetAssetThumbnails(); 

// Will raise the CollectionChanged notification 
AssetCollection = _assetModel.GetAssetThumbnails(); 

虽然我也看到很多人谁使用List或自定义集合,而不是ObservableCollection为好,这不会引发CollectionChanged事件。

+0

那么,当我捕获一个新的图像时,它只保存在ObservableCollection中的图像保存在同一个目录中。所以我认为我需要更改集合中的项目,而不是集合本身。你的例子非常有帮助,谢谢!我会尽量对你列出的一些变化进行检查,看看它们是否有效。 – Zajn

+0

我打算接受这个答案,因为这有助于我理解我在代码中做错了什么。我仍然无法正确地更新用户界面,但这超出了这个问题的范围,因为它与创建缩略图后未引发的事件有关。 – Zajn