I am familiar with BindingOperations.EnableCollectionSynchronization
to make WPF participate in locking access to an ObservableCollection
for use on multiple threads.
But does this place the same restriction on my use of a CollectionViewSource.View
that uses that ObservableCollection
as its source? Or does the view contain its own internal list?
For example, consider the following simplified view-model (which I admit I have not compiled) with a protected list of shapes that is publicly exposed from a CollectionViewSource
view. As long as I protect every use of the _shapes
collection with the _lock
object, I should be fine and WPF will like me.
But should I be locking the same _lock
object in the DoesViewContainShape
function?
public class MeasureVm
{
public MeasureVm()
{
BindingOperations.EnableCollectionSynchronization(_shapes, _lock);
_cvsShapes = new CollectionViewSource() { Source = _shapes, Filter = FilterShapes };
}
// WPF Binds to this
public ICollectionView Shapes => _cvsShapes.View;
private bool FilterShapes(object obj)
{
// Eventually some arbitrary code to filter out shapes
return true.
}
public void AddShape(shape)
{
// Any use of _shapes requires locking.
lock(_lock)
_shapes.Add(shape);
}
public bool DoesViewContainShape(Shape shape)
{
// SHOULD I LOCK HERE?
return _cvsShapes.View.Contains(shape);
}
private ObservableCollection<Shape> _shapes = new();
private CollectionViewSource _cvsShapes;
private object _lock = new();
}
You are confusing the ICollectionView interface (https://learn.microsoft.com/ru-ru/dotnet/api/system.componentmodel.icollectionview?view=windowsdesktop-8.0) with its implementation, the CollectionView class (https://learn.microsoft.com/en-us/dotnet/api/system.windows.data.collectionview?view=windowsdesktop-8.0). The ICollectionView interface does not impose restrictions on multithreading. The CollectionView class is derived from DispatcherObject, which itself ensures its thread safety, but also makes it single-threaded (in the thread that created it).
P.S.
I was simply noting that the only thing that I get from CollectionViewSource.View is the interface. Is that always implemented by an instance of the CollectionView class? Is that guaranteed?
In default implementations, the CollectionViewSource.View
property will always return a class derived from CollectionView
. But if desired, you can replace it with your own custom implementation of ICollectionView
, which will not be derived from CollectionView
. Although this is not excluded, but in all my practice, I have not encountered such a solution.
For "replacement", it is necessary that the source implements the ICollectionViewFactory
Interface.