更新到ListBox绑定集合后刷新UI

时间:2012-02-27 17:05:56

标签: wpf mvvm listbox observablecollection

我试图直观地显示一个项目(在我的情况下是一个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方法。我不知道我应该在哪里添加这个事件处理程序。我只使用代码隐藏文件将视图模型的数据上下文添加到视图中,就是这样。这是我通常认为添加任何事件处理的地方。谁能看到我在这里缺少的简单的东西?

1 个答案:

答案 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事件。