运行时清除ObservableCollection时的绑定错误

时间:2016-07-24 19:39:51

标签: wpf xaml data-binding observablecollection

我有一个完美的ObservableCollection,但是当我清除这个ObservableCollection时,我无法删除运行时出现的绑定错误:

System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=Icon; DataItem='NamedObject' (HashCode=40835417); target element is 'Image' (Name=''); target property is 'Source' (type 'ImageSource')

我制作了一个小代码来重现我在下面显示的问题:(查看):

    <Button Height="40" Width="40" Click="Button_Click"></Button>
    <ListBox ItemsSource="{Binding ProductList}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid IsItemsHost="True"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition/>
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Image Height="32" Source="{Binding Icon}" Stretch="Fill" Width="32"/>
                    <Label Grid.Row="1" Content="{Binding Description}"/>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    public ObservableCollection<Product> ProductList { get; set; }

    public void TestList()
    {
        ProductList = new ObservableCollection<Product>();
        ProductList.Add(new Product("Product1", "pack://application:,,,/Product1.png"));
        ProductList.Add(new Product("Product2", "pack://application:,,,/Product2.png"));
        ProductList.Add(new Product("Product3", "pack://application:,,,/Product3.png"));
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
         ProductList.Clear();          
         ProductList.Add(new Product("Product4", "pack://application:,,,/Product4.png"));            
    }

我的产品类:

public class Product : INotifyPropertyChanged
{
    #region "## INotifyPropertyChanged Members ##"
    public event PropertyChangedEventHandler _propertyChanged;

    public event PropertyChangedEventHandler PropertyChanged
    {
        add { this._propertyChanged += value; }
        remove { this._propertyChanged -= value; }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        App.Current.Dispatcher.BeginInvoke((Action)delegate
        {
            if (this._propertyChanged != null)
                this._propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        });
    }
    #endregion

    public string Description
    {
        get { return this.description; }
        set
        {
            this.description = value;
            this.OnPropertyChanged("Description");
        }
    }
    private string description;

    public BitmapImage Icon
    {
        get { return this.icon; }
        set
        {
            this.icon = value;
            this.OnPropertyChanged("Icon");
        }
    }
    private BitmapImage icon;

    public Product(string desc, string iconPath)
    {
        Description = desc;
        BitmapImage bi = new BitmapImage(new Uri(iconPath));
        bi.Freeze();
        Icon = bi;
    }
}

单击按钮时出现错误,执行以下行:              ProductList.Clear();

我做了很多测试:

  • 单独删除列表中的项目

  • 使用Fallback和TargetNullValue:

       <Image Height="32" Source="{Binding Icon, FallbackValue='pack://application:,,,/transparent.png', TargetNullValue='pack://application:,,,/transparent.png'}" Stretch="Fill" Width="32"/>
    

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

尝试删除TargetNullValue和FallbackValue并查看它是否仍然存在?如果不存在,则文件的URI存在问题。

另外请记住,如果您经常引用transparent.png,则会多次将相同的图像加载到内存中。而是考虑在您的ResourceDictionary中添加一行,如下所示:

<BitmapImage UriSource="/MyApp;component/Images/transparent.png" x:Key="Transparent" PresentationOptions:Freeze="True" />

然后像这样在XAML中使用:

<Image Height="32" Source="{Binding Icon, FallbackValue={StaticResource:Transparent}, TargetNullValue={StaticResource:Transparent}" Stretch="Fill" Width="32"/>

此更改会加载您的图像一次,但会在很多地方使用它来降低内存压力。