即使列表中的项目,ObservableCollection的Remove / Add方法也不起作用

时间:2018-11-21 05:50:37

标签: c# collections

我在添加和删除集合中的项目时遇到了一个小问题。

    private ObservableCollection<PrintDocumentSettingsModel> _AllPrintingFormats;
    public ObservableCollection<PrintDocumentSettingsModel> PrintingFormats
    {
        get
        {
            var formats = new ObservableCollection<PrintDocumentSettingsModel>(
                _AllPrintingFormats.Where(x => x.IsStandartPrinter == IsStandartPrinter));
            if (!formats.Contains(SelectedFormat))
                SelectedFormat = formats.FirstOrDefault();
            return formats;
        }
        set { _AllPrintingFormats = value; OnPropertyChanged("PrintingFormats"); }
    }

    private bool _IsStandartPrinter;
    public bool IsStandartPrinter
    {
        get { return _IsStandartPrinter; }
        set
        {
            _IsStandartPrinter = value;
            OnPropertyChanged("IsStandartPrinter");
            OnPropertyChanged("PrintingFormats");
        }
    }

    private void DeleteFormat()
    {
        if (SelectedFormat != null && SelectedFormat.IsEditable &&
            PrintingFormats.Contains(SelectedFormat))
        {
            PrintingFormats.Remove(SelectedFormat);
            OnPropertyChanged("PrintingFormats");
        }
    }

方法 DeleteFormat()不起作用,即使if语句返回true。但是,如果我将 PrintingFormats 替换为 _AllPrintingFormats 来重写 DeleteFormat(),则该方法将正常工作。

    private void DeleteFormat()
    {
        if (SelectedFormat != null && SelectedFormat.IsEditable &&
            _AllPrintingFormats.Contains(SelectedFormat))
        {
            _AllPrintingFormats.Remove(SelectedFormat);
            OnPropertyChanged("PrintingFormats");
        }
    }

那有什么窍门?

1 个答案:

答案 0 :(得分:2)

这不是编写属性的好方法。一个属性应该在您的类中返回一个私有对象(无论是显式还是隐式声明),但在某些情况下,该属性与任何实际的私有成员无关。

当您写这篇文章时:

    get
    {
        var formats = new ObservableCollection<PrintDocumentSettingsModel>(
            _AllPrintingFormats.Where(x => x.IsStandartPrinter == IsStandartPrinter));
        if (!formats.Contains(SelectedFormat))
            SelectedFormat = formats.FirstOrDefault();
        return formats;
    }
    set { _AllPrintingFormats = value; OnPropertyChanged("PrintingFormats"); }

您正在创建一个名为formats的新对象,并返回对该对象的引用。这与实际的私有成员_AllPrintingFormats没有关系。因此,当您调用PrintingFormats.Remove(SelectedFormat);时,它将尝试在formats的{​​{1}}函数中声明并实例化的get上进行操作。由于此更改是在其他对象上执行的,因此不会反映在PrintingFormats上。

此外,该更改完全无用,因为您将不会保留对_AllPrintingFormats的任何引用,并且稍后将对其进行垃圾回收。您拥有的代码在性能(每次调用该属性时在formats中创建一个新变量,以及使用LINQ创建变量)和空间(即使在get上的引用之后)都效率低下被释放,它将不会被GC直接清除,这意味着您将有多个formats僵尸对象等待收集并占用空间。

顺便说一句,在一个很可能被多个线程访问的集合上使用LINQ并不是一个好主意,因为您可能会遇到竞争条件。您必须了解这一行:

formats

将不会立即确定。也就是说,此调用不会获得满足LINQ标准的元素。您返回var formats = new ObservableCollection<PrintDocumentSettingsModel>( _AllPrintingFormats.Where(x => x.IsStandartPrinter == IsStandartPrinter)); 后,将在 上解决此问题,这意味着另一个线程所做的任何更改将在行和实际使用{{1}之间产生不同的结果。 }

如果您想维护该属性并将其保持不变,则始终可以执行问题第二部分中的操作,然后直接使用formats。但是,我建议将formats更改为:

_AllPrintingFormats

如果确实需要LINQ查询,则可以在PrintingFormats上执行此查询,而不是由属性来完成。