Search code examples
wpfdata-bindingdatagriddatacontextitemssource

WPF binding DataGrid to CollectionViewSource: working via DataContext, empty via ItemsSource; difference?


Consider the following XAML:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:c="clr-namespace:WpfApplication1"
    DataContext="{Binding Source={x:Static c:ViewModel.Instance}}"
    >
<Grid>
    <DataGrid DataContext="{Binding ItemsViewSource}" ItemsSource="{Binding}" />

</Grid>

and the view model:

public class ItemViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class ViewModel
{
    public static ViewModel Instance { get; set; }

    static ViewModel()
    {
        Instance = new ViewModel();
    }

    public ObservableCollection<ItemViewModel> Items { get; private set; }
    public CollectionViewSource ItemsViewSource { get; private set; }

    public ViewModel()
    {
        Items = new ObservableCollection<ItemViewModel>();
        ItemsViewSource = new CollectionViewSource() { Source = Items };
        Items.Add(new ItemViewModel() { FirstName = "test", LastName = "test" });
    }
}

This code is working, but if I change

<DataGrid DataContext="{Binding ItemsViewSource}" ItemsSource="{Binding}" />

to

<DataGrid ItemsSource="{Binding ItemsViewSource}" />`

DataGrid does not bind, it is empty.

What is the difference between these two bindings?


Solution

  • First of all for second option to work, you need to bind with CollectionViewSource.View property.

    <DataGrid ItemsSource="{Binding ItemsViewSource.View}" />
    

    When you bind DataContext of dataGrid to CollectionViewSource, dataGrid internally do value conversion from CollectionViewSource to ICollectionView (ListCollectionView in your case) but when you asked it explicitly to bind to CollectionViewSource, it doesn't do default value conversion. You can verify this by putting converter in your binding.