0
votes

I'm binding to a ListBox, and within the ListBox, another ListBox.

My model looks like

public interface ICriteriaDetail
{
    string Title { get; }
    int NumberOfEvents { get; }
    ICriteriaDetail ChildCriteria { get; }
}

So, I'm using a recursive approach for the children (not a list).

When I bind to my ListView, I get the items in a list, one under the other.

The issue is, the child item is not showing at all!

The dummy data

  public static IEnumerable<ICriteriaDetail> GetCriteriaList()
    {
        var list = new List<CompoundCriteria.Ui.Model.Interfaces.ICriteriaDetail>();
        list.Add(GetCriteriaDetail("My Title", 5, false));
        list.Add(GetCriteriaDetail("Other", 3, false));
        list.Add(GetCriteriaDetail("Biggy", 8, true));

        var child = new CompoundCriteria.Ui.Model.CriteriaDetail.CriteriaDetail("childAgain", 43, null);
        var child2 = new CompoundCriteria.Ui.Model.CriteriaDetail.CriteriaDetail("childAgainAgain", 13, child);

        list.Add(new CompoundCriteria.Ui.Model.CriteriaDetail.CriteriaDetail("Really big", 86, new CompoundCriteria.Ui.Model.CriteriaDetail.CriteriaDetail("smaller", 15, child2)));

        return list;
    }

    private static ICriteriaDetail GetCriteriaDetail(string title, int events, bool hasChild)
    {
        if (!hasChild)
            return new CompoundCriteria.Ui.Model.CriteriaDetail.CriteriaDetail(title, events, null);

        var child = new CompoundCriteria.Ui.Model.CriteriaDetail.CriteriaDetail("child" + title, 13 + events, null);
        return new CompoundCriteria.Ui.Model.CriteriaDetail.CriteriaDetail(title, events, child);
    }

The ViewModel

    public MainWindowViewModel()
    {
        this.Criterias = DatasourceMockup.GetCriteriaList();
    }

    private IEnumerable<ICriteriaDetail> _criterias;
    public IEnumerable<ICriteriaDetail> Criterias
    {
        get { return _criterias; }
        set { _criterias = value; }
    }

And the ListBox in the XAML

 <ListBox ItemsSource="{Binding Criterias}" >
                    <ListBox.Resources>
                         <ControlTemplate x:Key="con">
                            <StackPanel Orientation="Horizontal">
                            <StackPanel Margin="15">
                                <TextBlock Text="{Binding Title}" />
                                <TextBlock Text="Events: ">
                                <Run Text="{Binding NumberOfEvents}" />
                                </TextBlock>
                             </StackPanel>
                             <ListBox ItemsSource="{Binding ChildCriteria} Visibility="{Binding ChildCriteria, Converter={StaticResource HideIfNull}}">">
                                    <ListBox.Resources>
                                        <DataTemplate DataType="{x:Type cDetail:CriteriaDetail}">
                                                <TextBlock Text="{Binding Title}" />
                                        </DataTemplate>
                                    </ListBox.Resources>
                                </ListBox>
                            </StackPanel>
                        </ControlTemplate>

                        <HierarchicalDataTemplate DataType="{x:Type cDetail:CriteriaDetail}">
                                <Control Template="{StaticResource con}" />
                        </HierarchicalDataTemplate>
                    </ListBox.Resources>
                </ListBox>

After reading TreeView, HierarchicalDataTemplate and recursive Data it appears that HierarchicalDataTemplate will suffice (no need for a DataTemplate as well) but, I'm lost as to why I'm not seeing the result I expected (even if the children are not in the desired place, I'd still hope to see them)

EDIT

I have just added a converter which makes the ListBox (the one inside the ControlTemplate) hidden if the bound data is null. I have an outline (an empty ListBox) for just 1 of the 3 (which is correct) but it doesn't bind any of the content (the Title). The output window shows nothing of any use...

Please note, there is no limit of chidren. In the example above, there is a parent child relationship, but it could be parent-child-child-child etc

1

1 Answers

1
votes

1) It is hard to understand your purpose , why ListBox, if you have ChildCriteria in model, not IEnumerable<ICriteriaDetail>?

2) Also you have binding errors, i changed xaml to

<ListBox ItemsSource="{Binding Criterias}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <StackPanel Margin="15">
                            <TextBlock Text="{Binding Title}" />
                            <TextBlock Text="Events: ">
                                <Run Text="{Binding NumberOfEvents}" />
                            </TextBlock>
                </StackPanel>
                <TextBox Text="{Binding Path=DataContext.ChildCriteria.Title, 
                                        RelativeSource={RelativeSource Mode=FindAncestor, 
                                                        AncestorType={x:Type ListBoxItem}, 
                                                        AncestorLevel=1}}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

and got

My result

EDIT1: 1) I changed data model to

public class CriteriaDetail : ICriteriaDetail
{
    public CriteriaDetail(string title, int numberOfEvents, IEnumerable<ICriteriaDetail> childCriteria)
    {
        Title = title;
        NumberOfEvents = numberOfEvents;
        ChildCriteria = childCriteria;
    }

    public string Title { get; set; }
    public int NumberOfEvents { get; set; }
    public IEnumerable<ICriteriaDetail> ChildCriteria { get; set; }
}

2) Changed xaml to

<TreeView ItemsSource="{Binding Criterias}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding ChildCriteria}">
                <TextBlock Foreground="Red" Text="{Binding Title}"/>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
</TreeView>

3) Changed GetCriteriaDetail to

    private static ICriteriaDetail GetCriteriaDetail(string title, int events, bool hasChild)
    {
        if (!hasChild)
            return new CriteriaDetail(title, events, null);

        var child3 = new CriteriaDetail("child3" + title, 13 + events, null);
        var child2 = new CriteriaDetail("child2" + title, 13 + events, new ICriteriaDetail[] { child3 });
        var child1 = new CriteriaDetail("child1" + title, 13 + events, new ICriteriaDetail[] { child2 });


        return new CriteriaDetail(title, events, new ICriteriaDetail[] {child1});
    }

and got this. I think it looks more like you want result