我试图直观地显示一个项目(在我的情况下是一个BitmapImage)已经使用WPF / MVVM添加到ListBox中的一个集合中。为了给出一些背景知识,我正在使用捕获卡捕获流式视频,并且当视频流式传输时我正在拍摄静态图像。通过单击UI上的“静止图像”按钮捕获这些图像。在捕获图像之后,我想在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;
}
我的ViewModel在其构造函数中创建模型的新实例,然后将公共属性AssetCollection
设置为_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
未被调用。我通过调试注意到它在检查时始终为null,因此永远不会调用OnPropetyChanged
方法。我不知道我应该在哪里添加这个事件处理程序。我只使用代码隐藏文件将视图模型的数据上下文添加到视图中,就是这样。这是我通常认为添加任何事件处理的地方。谁能看到我在这里缺少的简单的东西?
答案 0 :(得分: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
事件。