I'm trying to populate a combobox with an observable collection and a header row using a composite collection. The header is there but I can't get the OC objects to populate. I'm just starting to use OC's so might be something basic I'm missing.
Customer class:
public class Customer : ViewModelBaseMain
{
public string CustomerName { get; set; }
public int CustomerId { get; set; }
}
I populate the OC, which is a dependency property, from a datatable (I verified that the OC is being populated correctly):
ObservableCollection<Customer> dpCustomerListOC = new ObservableCollection<Customer>();
foreach (DataRow drow in dpHeaderCustTable.Rows)
{
Customer Customer = new Customer();
Customer.CustomerId = Convert.ToInt32(drow["customer_id"]);
Customer.CustomerName = drow["customer_name"].ToString();
dpCustomerListOC.Add(Customer);
}
In the usercontrol resources, I specify the VM as a static resource:
<local:ReservationViewModel x:Key="ReserveVM"/>
I've tried two different ways from posts I've read.
First way w/ collection in the resources using x:reference:
<ComboBox x:Name="cboCustHeader" Grid.IsSharedSizeScope="True" IsEditable="False"
ItemsSource="{DynamicResource items}">
<ComboBox.Resources>
<CompositeCollection x:Key="items">
<ComboBoxItem IsEnabled="False">
<Border Style="{StaticResource ComboHeaderBorder}">
<Grid Style="{StaticResource ComboHeaderStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="7"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Grid.Column="0" Text="ID"/>
<TextBlock Grid.Column="2" Text="Name"/>
</Grid.Children>
</Grid>
</Border>
</ComboBoxItem>
<CollectionContainer Collection="{Binding Source={x:Reference cboCustHeader}, Path=DataContext.dpCustomerListOC}"/>
</CompositeCollection>
</ComboBox.Resources>
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="7"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Text="{Binding Path=CustomerId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding Path=CustomerName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid.Children>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Second way specifying the source:
<ComboBox x:Name="cboCustHeader" Grid.IsSharedSizeScope="True">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem IsEnabled="False">
<Border Style="{StaticResource ComboHeaderBorder}">
<Grid Style="{StaticResource ComboHeaderStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="7"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Grid.Column="0" Text="ID"/>
<TextBlock Grid.Column="2" Text="Name"/>
</Grid.Children>
</Grid>
</Border>
</ComboBoxItem>
<CollectionContainer Collection="{Binding Path=dpCustomerListOC, Source={StaticResource ReserveVM}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="7"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Grid.Column="0" Text="{Binding Path=CustomerId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Column="2" Text="{Binding Path=CustomerName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid.Children>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
Add a public property exposing the collection on your view model:
public ObservableCollection<Customer> DpCustomerListOC
{
get { return dpCustomerListOC; }
}
And bind the combo's ItemsSource
to it:
<ComboBox x:Name="cboCustHeader" Grid.IsSharedSizeScope="True">
<ComboBox.ItemsSource>
<CompositeCollection>
<ComboBoxItem IsEnabled="False">
<Border Style="{StaticResource ComboHeaderBorder}">
<Grid Style="{StaticResource ComboHeaderStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="7"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Grid.Column="0" Text="ID"/>
<TextBlock Grid.Column="2" Text="Name"/>
</Grid.Children>
</Grid>
</Border>
</ComboBoxItem>
<CollectionContainer Collection="{Binding Path=DpCustomerListOC, Source={StaticResource ReserveVM}}"/>
</CompositeCollection>
</ComboBox.ItemsSource>
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition Width="7"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<Grid.Children>
<TextBlock Grid.Column="0" Text="{Binding Path=CustomerId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Column="2" Text="{Binding Path=CustomerName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Grid.Children>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Make sure the collection is populated in the constructor.