Reputation: 97
Can anybody please tell what im missing trying to make a 'nested' WPF ItemsControl ... if it even can work the way I want it. I have this data model:
public class PlateItem
{
public Guid ID { get; set; }
public string Type { get; set; }
public string Caption { get; set; }
public int GridRow { get; set; }
public int GridColumn { get; set; }
// 0 or 2 Children
public ObservableCollection<PlateItem> Children { get; set; }
}
private void Initialize()
{
ObservableCollection<PlateItem> collection = new ObservableCollection<PlateItem>();
// Type = "Child" - Caption should be displayed
// Type = "Container" - Caption should not be displayed. Its Children of type "Visual" Captions should be displayed
PlateItem item_Main = new PlateItem() { Type = "Container", Caption = "ZERO", GridRow = 0, GridColumn = 0, ID = Guid.NewGuid(), Children = new ObservableCollection<PlateItem>() };
PlateItem item_Main_A = new PlateItem() { Type = "Child", Caption = "ONE", GridRow = 0, GridColumn = 0, ID = Guid.NewGuid(), Children = new ObservableCollection<PlateItem>() };
PlateItem item_Main_B = new PlateItem() { Type = "Container", Caption = "TWO", GridRow = 1, GridColumn = 0, ID = Guid.NewGuid(), Children = new ObservableCollection<PlateItem>() };
PlateItem item_Main_B_1 = new PlateItem() { Type = "Child", Caption = "THREE", GridRow = 0, GridColumn = 0, ID = Guid.NewGuid(), Children = new ObservableCollection<PlateItem>() };
PlateItem item_Main_B_2 = new PlateItem() { Type = "Child", Caption = "FOUR", GridRow = 1, GridColumn = 0, ID = Guid.NewGuid(), Children = new ObservableCollection<PlateItem>() };
item_Main_B.Children.Add(item_Main_B_1);
item_Main_B.Children.Add(item_Main_B_2);
item_Main.Children.Add(item_Main_A);
item_Main.Children.Add(item_Main_B);
collection.Add(item_Main);
this.PlateItemsSource = collection;
}
And I need a nested control that would:
Now I have this XAML, which doesnt work:
<UserControl.Resources>
<!-- ************************************************** -->
<h:TemplateselectorPlateItem x:Key="TemplateselectorPlateItem"/>
<!-- should display PlateItems that don't have Children -->
<DataTemplate x:Key="DatatemplatePlateItemSingle">
<TextBox Background="Green" Margin="20"
Text="{Binding Path=Caption, Mode=TwoWay}" />
</DataTemplate>
<!-- should display PlateItems that has Children -->
<DataTemplate x:Key="DatatemplatePlateItemDouble">
<ItemsControl ItemsSource="{Binding Path=Children}"
ItemTemplate="{StaticResource DatatemplatePlateItemSingle}">
<ItemsControl.ItemContainerStyle>
<Style>
<Style.Setters>
<Setter Property="Grid.Row" Value="{Binding Path=GridRow}"/>
<Setter Property="Grid.Column" Value="{Binding Path=GridColumn}"/>
</Style.Setters>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</UserControl.Resources>
<ItemsControl ItemsSource="{Binding Path=PlateItemsSource}"
ItemTemplateSelector="{StaticResource TemplateselectorPlateItem}">
</ItemsControl>
Code for the TemplateSelector:
public class TemplateselectorPlateItem : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (element != null && item != null && item is PlateItem)
{
PlateItem plateItem = item as PlateItem;
if(plateItem.Children.Count == 0)
{
return element.FindResource("DatatemplatePlateItemSingle") as DataTemplate;
}
else
{
return element.FindResource("DatatemplatePlateItemDouble") as DataTemplate;
}
}
return null;
}
}
Very rough visual representation of what Im trying to achieve http://www.trinitytilesupply.com/pattern2.jpg Why I want to use such model - I will need functionality to split any "Visual" vertically or horisontally, in code that would mean - change a source PlateItem: "Child"-type to "Container"-type with 2 new children
Upvotes: 0
Views: 438
Reputation: 1425
You need to tweak DatatemplatePlateItemDouble, remove its ItemTemplate, instead use the same ItemTemplateSelector. So it would recursively apply DatatemplatePlateItemDouble to all descendants with children.
<DataTemplate x:Key="DatatemplatePlateItemDouble">
<ItemsControl ItemsSource="{Binding Path=Children}"
ItemTemplateSelector="{StaticResource TemplateselectorPlateItem}" >
...
You also need to change/remove this line which will cause infinite recursion.
item_Main.Children.Add(item_Main);
Once you do that you should get
Upvotes: 1