Using an ItemsControl with a WrapPanel set as the ItemsPanel, I am trying to achieve what is illustrated in this image:
The XAML looks like this (modified to make it more simple):
<ItemsControl ItemsSource="{Binding Animals}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Margin="5">
<Image Source="{Binding ImageUrl}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The underlying ViewModel looks like this:
public class Zoo
{
public ObservableCollection<Animal> Animals { get; set; } = new ObservableCollection<Animal>();
public ICommand AddAnimal() => new DelegateCommand(() => Animals.Add(new Animal()));
}
public class Animal
{
public string ImageUrl { get; set; }
}
The ItemsControl's DataContext is set to an instance of Zoo and populated with 4 Animals.
The question: How can I add a "static" child element that looks like the other elements, is a child of the WrapPanel, and wraps with the other children? Specifically, I want the last element to be an add-button (the green plus-sign shown in the image above), which is bound to the AddAnimal Command property of the Zoo.
Requirements:
I have thought about:
Additional information: I use: WPF, PRISM, C# 6.0, .NET 4.0 Client Profile and the MVVM pattern.
Any thoughts on this problem?
Solution:
@kyriacos_k's answers solved it for me with two minor modification:
In the end this is what worked for me:
<ItemsControl>
<ItemsControl.Resources>
<CollectionViewSource x:Key="AnimalCollection" Source="{Binding Animals}"/>
<behaviors:BindingProxy x:Key="Proxy" DataContext="{Binding}"/>
<DataTemplate DataType="{x:Type local:Animal}">
<Border Margin="5">
<Image Source="{Binding ImageUrl}" />
</Border>
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource AnimalCollection}}"/>
<Border Margin="5">
<Button Command="{Binding DataContext.AddAnimal, Source={StaticResource Proxy}}">
<Image Source="SourceToPlusSign"/>
</Button>
</Border>
</CompositeCollection>
</ItemsControl.ItemsSource>
</ItemsControl>
The code for the BindingProxy is here (snatched directly from: Binding Visibility for DataGridColumn in WPF):
public class BindingProxy : Freezable
{
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
public object DataContext
{
get { return GetValue(DataContextProperty); }
set { SetValue(DataContextProperty, value); }
}
public static readonly DependencyProperty DataContextProperty =
DependencyProperty.Register("DataContext", typeof(object),
typeof(BindingProxy));
}
You can do it in a very neat way, using the CompositeCollection
<ItemsControl>
<ItemsControl.Resources>
<CollectionViewSource x:Key="AnimalCollection" Source="{Binding Animals}"/>
</ItemsControl.Resources>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Margin="5">
<Image Source="{Binding ImageUrl}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource AnimalCollection}}"/>
<Border Margin="5">
<Button Command="{Binding AddAnimal}">
<Image Source="YourAddButtonSource"/>
</Button>
</Border>
</CompositeCollection>
</ItemsControl.ItemsSource>
</ItemsControl>
Of course, if you want the add button to appear first, just swap the order of the Border
(containing the Button
) with the CollectionContainer
in the CompositeCollection
tag.
Take a look at CompositeCollection. It lets you add additional items to an ItemsSource
binding:
<Window.Resources>
<CollectionViewSource x:Key="AnimalViewSource" Source="{Binding Animals}"/>
</Window.Resources>
<ItemsControl>
<ItemsControl.ItemsSource>
<CompositeCollection>
<local:Animal ImageUrl="somepath/plussign.png" />
<CollectionContainer Collection="{Binding Source={StaticResource AnimalViewSource}}"/>
</CompositeCollection>
</ItemsControl.ItemsSource>
... ItemsPanel, ItemsTemplate, etc. follow here ...
</ItemsControl>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With