Should I Bind to Icollectionview or Observablecollection

Should I bind to ICollectionView or ObservableCollection

You always bind to an ICollectionView, whether you make it explicit or not.

Assume that we have

var collection = new ObservableCollection<string>();
var collectionView = CollectionViewSource.GetDefaultView(collection);

In this case, binding to collection or to collectionView is one and the same: the binding engine will bind to the default collection view (which is reference equal to collectionView) if you tell it to bind to collection.

This means that the answer to your question is "it makes absolutely no difference".

Just to be totally clear: even if you bind to the collection directly, the binding engine will bind to the default view. Modifying properties of the view such as sort criteria will affect the binding that appears to bind directly to the collection, since behind the covers it's a binding to the default view instead.

However, there is another interesting and related question: should one bind to the default collection view (i.e., to the collection itself, because there's no reason to explicitly bind to the default view) or to another view of the same collection?

Considering that each view has its own notion of current item, sort criteria, etc, it follows that if you intend to have multiple bindings to the same collection, and the bound controls need to have distinct notions of current item, filters and company, then what you want is to explicitly bind to multiple views of the same underlying collection.

Filtering ObservableCollection with ICollectionView

You would need to:

public class MainViewModel : ViewModelBase, IBarcodeHandler
{
public ICollectionView TraceItemCollectionView
{
get { return CollectionViewSource.GetDefaultView(TraceItemCollectionViewSource); }
}

public ObservableCollection<TraceDataItem> TraceItemCollectionViewSource { get; set; }
}

then, somewhere in the code (maybe in the constructor) add your filter:

TraceItemCollectionView.Filter = o =>
{
var item = (TraceDataItem) o;

//based on item, return true if it should be visible, or false if not

return true;
};

And, in XAML, you would need to change the binding to TraceItemCollectionView property.

WPF Binding filtered ObservableCollection ICollectionView to Combobox

All collections have a default CollectionView. WPF always binds to a view rather than a collection. If you bind directly to a collection, WPF actually binds to the default view for that collection. This default view is shared by all bindings to the collection, which causes all direct bindings to the collection to share the sort, filter, group, and current item characteristics of the one default view.

try creating CollectionViewSource and setting its filtering logic like this:

//create it as static resource and bind your ItemsControl to it
<CollectionViewSource x:Key="csv" Source="{StaticResource MotionSequenceCollection}"
Filter="CollectionViewSource_Filter">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="YYY"/>
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="YYY" Direction="Ascending"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>

private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
var t = e.Item as ModelBase;
if (t != null)

{
//use your filtering logic here

}
}

Observable binding to two ICollectionView of same collection

You should use the approach outlined in the remarks section of the documentation of the CollectionView class:

To create a collection view for a collection that only implements IEnumerable, create a CollectionViewSource object, add your collection to the Source property, and get the collection view from the View property.

This approach is the equivalent to CollectionViewSource.GetDefaultView, i.e. you will use the retrieved View just the same:

  • You bind it to the UI
  • You use it to filter
  • You use it to sort

Binding a CollectionViewSource to ObservableCollection

It will work this way:

<ListBox ItemsSource="{Binding}">
<ListBox.DataContext>
<CollectionViewSource Source="{Binding Path=DocProps1}">
</CollectionViewSource>
</ListBox.DataContext>
</ListBox>

This article XAML Binding to a CollectionViewSource property on a ViewModel has some explanations of this behaviour

ObservableCollection and CollectionView

The property Collection has a reference to the view of the ObservableDVD. Being a reference means pointing to the same data in memory.

ObservableCollection Class Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.

ICollectionView within CompositeCollection

CollectionViewSource should be part of UI as you need the PresentationFramework.dll to use it.

As for the structure I usually have this:

in xaml:

<CollectionViewSource Source="{Binding CmbList}" x:Key="cmbList"></CollectionViewSource>
<CollectionViewSource Source="{Binding Items}" x:Key="items"></CollectionViewSource><!-- this goes into your Resources tag

<ComboBox>
<ComboBox.ItemsSource><!-- in here we are using multiple types of collections and objects
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource items}}"></CollectionContainer>
<sys:String>Newly added item</sys:String>
<CollectionContainer Collection="{Binding Source={StaticResource cmbList}}"></CollectionContainer>
</CompositeCollection>
</ComboBox.ItemsSource>
</ComboBox>

where xmlns:sys="clr-namespace:System;assembly=mscorlib"
And my ViewModel has this as the collections defined:

private string[] _items;

public string[] Items
{
get { return _items; }
set { _items = value; OnPropertyChanged("Items"); }
}
private List<int> _cmbList;

public List<int> CmbList
{
get { return _cmbList; }
set { _cmbList = value; OnPropertyChanged("CmbList"); }
}

As you will see this will display the 2 very different types of collections plus additional item that we created.



Related Topics



Leave a reply



Submit