Dester Dezzods
Dester Dezzods

Reputation: 1535

WPF add extra item to bound collection

I have a ItemsControlwhich have bound items. As you can see in the screenshot, those items are bound to a property and I want an extra item appear which will have totally different behaviour than the other items. How can I achieve this (preferabelly with xaml only)?

Screenshot for what I want

Upvotes: 2

Views: 2253

Answers (2)

kurin123
kurin123

Reputation: 363

Take a look at Composite Collection. Wpf example here or here.

Based on comment, here is sample code from first example

<ComboBox>
    <ComboBox.ItemsSource>
        <CompositeCollection>
            <ComboBoxItem Content="All" />
            <CollectionContainer Collection="{Binding Source={StaticResource AllBitsSource}}" />
        </CompositeCollection>
    </ComboBox.ItemsSource>
</ComboBox>

Edit - MVVM

The issue with CollectionContainer is that is does not have access to curent DataContext. StaticResource solves it

xaml

<Window x:Class="WpfApplication5.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplication5"
        Title="MainWindow" Height="300" Width="525" FontSize="25">

    <StackPanel Name="stk">
        <StackPanel.Resources>
            <CollectionViewSource x:Key="cvsBooks" Source="{Binding Path=Books}" />
        </StackPanel.Resources>

        <ListBox>
            <ListBox.ItemsSource>
                <CompositeCollection>
                    <ListBoxItem>
                        <StackPanel>
                            <TextBlock Margin="5,0">Not tagged</TextBlock>
                        </StackPanel>
                    </ListBoxItem>
                    <CollectionContainer Collection="{Binding Source={StaticResource cvsBooks}}"/>
                </CompositeCollection>
            </ListBox.ItemsSource>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <Button Content="Add" Click="Button_Click"/>
    </StackPanel>
</Window>

C#

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        var vm = new ViewModel();
        this.stk.DataContext = vm;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        //should be Command in MVVM, but this is just example to see that ObservableCollection works
        var btn = sender as Button;
        (btn.DataContext as ViewModel).Books.Add(new Book() { Name = "Book" + DateTime.Now.Second });
    }

}

public class ViewModel
{
    public ViewModel()
    {
        this.Books = new ObservableCollection<Book>();
        this.Books.Add(new Book() { Name = "Book 1" });
        this.Books.Add(new Book() { Name = "Book 2" });
        this.Books.Add(new Book() { Name = "Book 3" });
    }

    public ObservableCollection<Book> Books { get; private set; }
}

public class Book
{
    public string Name { get; set; }
}

Upvotes: 6

ΩmegaMan
ΩmegaMan

Reputation: 31606

which will have totally different behaviour than the other items.

Behavior is done with styles. I will provide a listbox example which is translatable to the ItemsControl.


Say for example we have an Order class with these properties

public class Order
{
    public string CustomerName { get; set; }
    public int OrderId { get; set; }
    public bool InProgress { get; set; }
}

When an order is marked as in progress (InProgress = true) we want to show red in our list box say for "Alpha" and "Omega" which are in progress:

enter image description here

ListBox Xaml

Here is the Xaml which binds to our data (how you bind is up to you) and shows how to work with Style(s), DataTemplate, and DataTrigger(s) to achieve that:

<ListBox ItemsSource="{StaticResource Orders}"
         x:Name="lbOrders">
    <ListBox.Resources>
        <DataTemplate DataType="{x:Type model:Order}">
            <TextBlock Text="{Binding Path=CustomerName}" />
        </DataTemplate>
        <Style TargetType="{x:Type ListBoxItem}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=InProgress}"
                             Value="True">
                    <Setter Property="Foreground"
                            Value="Red" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.Resources>
</ListBox>

Here is the data setup in the pages's resource Xaml to do that, but it could be created in code behind:

<Window.Resources>
    <model:Orders x:Key="Orders">
        <model:Order CustomerName="Alpha"
                        OrderId="997"
                        InProgress="True" />
        <model:Order CustomerName="Beta"
                        OrderId="998"
                        InProgress="False" />
        <model:Order CustomerName="Omega"
                        OrderId="999"
                        InProgress="True" />
        <model:Order CustomerName="Zeta"
                        OrderId="1000"
                        InProgress="False" />
    </model:Orders>
</Window.Resources>

Now its just a question of what property your added item will have which will trigger a different style.

Upvotes: 0

Related Questions