CompositeCollection/CollectionViewSource confusion
Asked Answered
S

1

7

I'm a little confused about how the data binding works when using these types.

I've read that you can't do the following

public partial class Window1 : Window
    {
        public ObservableCollection<string> Items { get; private set; }

        public Window1()
        {
            Items = new ObservableCollection<string>() { "A", "B", "C" };
            DataContext = this;
            InitializeComponent();
        }
    }

<Window x:Class="WpfApplication25.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ComboBox>
        <ComboBox.ItemsSource>
            <CompositeCollection>
                <CollectionContainer Collection="{Binding Items}"/>
            </CompositeCollection>
        </ComboBox.ItemsSource>
    </ComboBox>
</Window>

because CompositeCollection has no notion of datacontext and so anything inside of it using a binding has to set the Source property. Such as the following :

<Window x:Class="WpfApplication25.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Window.Resources>
        <CollectionViewSource x:Key="list" Source="{Binding Items}"/>
    </Window.Resources>

    <ComboBox Name="k">
        <ComboBox.ItemsSource>
            <CompositeCollection>
               <CollectionContainer Collection="{Binding Source={StaticResource list}}"/>
            </CompositeCollection>
        </ComboBox.ItemsSource>
    </ComboBox>
</Window>

But how is that working? it sets the source to something, but that something, in this case a CollectionViewSource uses a datacontext (as its not explicitly setting a source).

So because "list" is declared in the resources of Window, does that mean it gets Windows DataContext? In which case, why doesn't the following also work?

<Window x:Class="WpfApplication25.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Window.Resources>
        <Button x:Key="menu" Content="{Binding Items.Count}"/>
    </Window.Resources>

    <ComboBox Name="k">
        <ComboBox.ItemsSource>
            <CompositeCollection>
                <ContentPresenter Content="{Binding Source={StaticResource menu}}"/>
            </CompositeCollection>
        </ComboBox.ItemsSource>
    </ComboBox>
</Window>
Sikko answered 22/5, 2013 at 22:56 Comment(0)
C
4

you are right CompositeCollection has no notion of datacontext so it cant inherit it from its parent.

from MSDN:
CompositeCollection can contain items such as strings, objects, XML nodes, elements, as well as other collections. An ItemsControl uses the data in the CompositeCollection to generate its content according to its ItemTemplate. For more information about using ItemsControl objects to bind to collections, see the Binding to Collections section of the Data Binding Overview.

to your question
But how is that working? it sets the source to something, but that something, in this case a CollectionViewSource uses a DataContext (as its not explicitly setting a source).

I guess you over think it, the Collection DependecyProperty can bind to any IEnumerable type so it doesn't matter how the collection was created as long as its created and implements IEnumerable.
in your case the CVS inherits the DataContext from the Window and then binds to Items.

regarding your second example it doesn't work because the ContentPesenter needs dataContext to work so since it could inherit it, the binding mechanism just set itself as the dataContext even though you tried binding the content Source to the button, you forgot to set the path, I guess this is why it got ignored. all you have to do to make it work is just set it like that:

<ContentPresenter Content="{Binding Source={StaticResource menu}, Path=Content}"/
Clank answered 11/7, 2013 at 14:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.