Sebastian
Sebastian

Reputation: 4811

Multi level expander WPF

I have below data structure

public class enrichment
{
    public string name { get; set; }
    public string type { get; set; }
}

public class Pages
{
    public string name { get; set; }
    public List<enrichment> enrichment { get; set; }
    public string label { get; set; }
}

public class SubChapter
{
    public string name { get; set; }
    public string id { get; set; }
    public List<Pages> pages { get; set; }
    public string parentId { get; set; }
}

public class Chapter
{
    public string name { get; set; }
    public string id { get; set; }
    public List<Pages> pages { get; set; }
    public List<SubChapter> chapters { get; set; }
}
public class TOCData
{
    public List<Chapter> chapters { get; set; }
}

And sample data looks like this

Chapter 1
  page 1
  page 2
  Chapter 1.1 
      page a
      page b          
Chapter 2 
   page 3
Chapter 3 
   chapter 3.1
      page c
      page d          

I want to present this data in an expander control and i been able to did it for 2 levels using the structure explained here http://pastebin.com/W8Nx857K But i cant repeat it to next level ( ie when a chapter contain sub chapter ) How can i represent it on my expander. What i did was Chapter - bind Pages in an expander. My question is how to add Chapters as well. Whether can i bind it simply or do i need to create controls manually Is any examples or modifications to code suggestions

Upvotes: 0

Views: 931

Answers (2)

Gope
Gope

Reputation: 1778

Usually you can either use a TreeView with a customized Template containing expander. Should take 1/2 hour or if your structure is really strict you create 2 Controls (ChapterViewer and PageViewer and derive both from ItemsControl. Their DataContext will be your corresponding classes. Then you can define DataTemplates for them, meaning a Chapter will be visually represented by a ChapterViewer and a Page by a PageViewer. This allows you to build up your structure the way you want. But it's a little fixed in structure. I would go with the templated TreeView.

EDIT----> This is code from the sample I created (http://1drv.ms/Tdq2Re):

ViewModel.cs (basic data structure):

public ViewModel()
        {
            this.TocData = new TOCData
            {
                Name = "Chapters",
                Chapters = new ObservableCollection<Chapter>
                {
                    new Chapter{ Name="Chapter 1", 
                        Elements = new ObservableCollection<ViewModelBase>
                        {
                            new Chapter
                            {
                                Name = "Introduction", 
                                Elements = new ObservableCollection<ViewModelBase>
                                {
                                    new Page(){Label = "Page I"},
                                    new Page(){Label = "Page II"},
                                    new Page(){Label = "Page III"}
                                }
                            },
                            new Page(){Label = "Page 1"},
                            new Page(){Label = "Page 2"},
                            new Page(){Label = "Page 3"},
                            new Page(){Label = "Page 4"},
                        }},            
                    new Chapter{ Name="Chapter 2", Elements = new ObservableCollection<ViewModelBase>
                        {              
                            new Page(){Label = "Page 5"},
                            new Page(){Label = "Page 6"},
                            new Page(){Label = "Page 7"},
                            new Page(){Label = "Page 8"},
                        }},
                }
            };
        }

It is used like that:

<Grid>
   <local:ChapterControl ItemsSource="{Binding Path=TocData.Chapters}"  />
</Grid>

The ChapterControl.xaml.cs (CustomControl):

 public class ChapterControl : ItemsControl
    {
        static ChapterControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ChapterControl), new FrameworkPropertyMetadata(typeof(ChapterControl)));
        }
    }

And the Styles, etc. for the control:

<!-- Chapter Template -->
    <DataTemplate x:Key="ChapterTemplate"  DataType="local:Chapter">
        <StackPanel>
            <local:ChapterControl  ItemsSource="{Binding Path=Elements}" />
        </StackPanel>
    </DataTemplate>

    <!-- Page Template -->
    <DataTemplate x:Key="pageTemplate"  DataType="local:Page">
        <TextBlock Text="{Binding Label}" Margin="25,0,0,0" />
    </DataTemplate>

    <local:ChapterItemStyleSelector x:Key="chapterItemStyleSelector" PageTemplate="{StaticResource pageTemplate}" ChapterTemplate="{StaticResource ChapterTemplate}" />

    <Style TargetType="{x:Type local:ChapterControl}">
        <Setter Property="ItemTemplateSelector" Value="{StaticResource chapterItemStyleSelector}" />
        <Setter Property="Margin" Value="10,0,0,0" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ChapterControl}">
                    <Expander Header="{Binding Name}">
                        <ItemsPresenter />
                    </Expander>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Upvotes: 1

Tzah Mama
Tzah Mama

Reputation: 1567

My suggestion is get rid of SubChapter and change Chapter's list to List<Chapter>.

Then create a UserControl for Chapter that contains an Expander, a ListBox for pages and a ListBox for Chapters.

This way your hierarchy should work without any problem .

Upvotes: 0

Related Questions