问题
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?
回答1:
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
回答2:
You can create List of objects, add Movies and then add another type for instance "string" object. Then you need to create class deriving from DataTemplateSelector which goes throughout List and determines whether element is Movie object. If so then it returns proper DataTemplate otherwise it return DataTemplate for button.
class DTS : DataTemplateSelector
{
public DataTemplate MovieTemplate { get; set; }
public DataTemplate ButtonTemplate { get; set; }
public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
{
return item is Movie ? MovieTemplate : ButtonTemplate;
}
}
then in XAML you do
<local:DTS x:Key="DTS" ButtonTemplate="{StaticResource ButtonTemplate}" MovieTemplate="{StaticResource MovieTemplate}"/>
Bear in mind that ButtonTemplate and MovieTemplate must be created before applying them since StaticResource demands this. MovieTemplate is the same template which you already have, only provide template in case of string for your Button. At the end you set ItemTemplateSelector as follows
<ListBox ItemsSource="{Binding lista}" ItemTemplateSelector="{StaticResource DTS}"/>
As a result you are supposed to be displayed
来源:https://stackoverflow.com/questions/25413252/wpf-listbox-with-multiple-sources-of-different-types