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 aCollectionViewSource
object, add your collection to theSource
property, and get the collection view from theView
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
Write Device Platform Specific Code in Xamarin.Forms
How to Get the Text of a Messagebox When It Has an Icon
Best Way to Switch Behavior Based on Type
Mvvm Show New Window from Vm When Seperated Projects
Ftp Directory Partial Listing with Wildcards
Wpf Webbrowser Mouse Events Not Working as Expected
Dynamically Switch Wcf Web Service Reference Url Path Through Config File
Switch Between Dotnet Core Sdk Versions
Execute Multiple Queries in Single Oracle Command in C#
Why "Decimal" Is Not a Valid Attribute Parameter Type
How to Convert a System.Io.Stream to a Windows.Storage.Streams.Irandomaccessstream
Rotate a Graphics Bitmap at Its Center
Collection Was Modified; Enumeration May Not Execute Error When Removing a Listitem from a Listbox
Best Way to Share Data Between Two Child Components in Blazor
Get Connectionstring from Appsettings.JSON Instead of Being Hardcoded in .Net Core 2.0 App