Search code examples
wpflistboxitemssourcemultibinding

WPF ListBox with multiple sources of different types


I was actually setting up a sample application for something entirely different, but then I was trying this:

I have a collection of Movies. I'll have a list box which displays all the movies. The list box, however, provides them as buttons, so that you can click onto a button and play the movie.

The code is:

<StackPanel DockPanel.Dock="Top">
    <ListBox ItemsSource="{Binding Movies}" SelectedItem="{Binding Path=SelectedMovie}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel IsItemsHost="True"
                           Width="{Binding (FrameworkElement.ActualWidth),
                                   RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Button Content="{Binding Title}"
                        Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},
                                  Path=DataContext.PlayMovieCommand}"
                        CommandParameter="{Binding Id}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</StackPanel>

Then I was thinking of adding a single Button to the end, with the text "Add", and when I click onto that button, I can add a new movie.

I don't find a solution to provide this. While searching the Internet I found HierarchicalDataTemplate and CompositeCollection; both looking promising at first, but I failed to get it working as I want. I was thinking of MultiBinding, too, but again I seem to fail.

So, I guess my question is:
How can I add a single Add-button to my collection of movies?

Or more generic: How can I add several sources/collections of data of different types to a list box?


Solution

  • Use CompositeCollection and DataTemplate for types.

    <Page
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
      <Page.Resources>
        <XmlDataProvider x:Key="MoviesData" XPath="Movies/Movie">
          <x:XData>
          <Movies xmlns="">
            <Movie Title="The Shawshank Redemption" />
            <Movie Title="The Godfather" />
            <Movie Title="The Dark Knight" />
          </Movies>
          </x:XData>
        </XmlDataProvider>
        <XmlDataProvider x:Key="MyButtonsData" XPath="MyButtons/MyButton">
          <x:XData>
          <MyButtons xmlns="">
            <MyButton Title="Add Movie" />
          </MyButtons>
          </x:XData>
        </XmlDataProvider>
        <DataTemplate DataType="Movie">
          <Button Content="{Binding XPath=@Title}"
                  Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},
                            Path=DataContext.PlayMovieCommand}"
                  CommandParameter="{Binding Id}" />
      </DataTemplate>
        <DataTemplate DataType="MyButton">
          <Button Content="{Binding XPath=@Title}"
                  Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},
                            Path=DataContext.AddMovieCommand}" />
      </DataTemplate>  
    
      </Page.Resources>
        <ListBox>
          <ListBox.ItemsSource>
            <CompositeCollection>
            <CollectionContainer Collection="{Binding Source={StaticResource MoviesData}}"/>
            <CollectionContainer Collection="{Binding Source={StaticResource MyButtonsData}}"/>
            </CompositeCollection>
          </ListBox.ItemsSource>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel IsItemsHost="True"
                               Width="{Binding (FrameworkElement.ActualWidth),
                                       RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>
    </Page>
    

    Here is the result in Kaxaml

    enter image description here