Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make an "Accordion Widget" in WPF?

The goal:

I'm trying to achieve something like this in WPF:

Widget with several vertically stacked expanders
(source: wordpress.org)


An initial solution:

At the moment, I'm trying to use an ItemsControl with an ItemTemplate composed of an Expander.

I want a consistent look for the Header portion of the Expander, but I want the Content portion of the Expander to be completely flexible. So, it's basically a set of "portlets" stacked vertically, where each portlet has a consistent title bar but different content.


The code so far:

This is what I have at the moment:

<ItemsControl
    Grid.Row="2"
    Grid.Column="2">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Expander>
                <Expander.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel
                            Orientation="Horizontal">
                            <TextBlock
                                FontSize="14"
                                FontWeight="Bold"
                                Text="Title_Of_Expander_Goes_Here" />
                            <TextBlock
                                Margin="10,0,0,0"
                                FontWeight="Bold"
                                FontSize="18"
                                Text="*" />
                        </StackPanel>
                    </DataTemplate>
                </Expander.HeaderTemplate>
                <Expander.Template>
                    <ControlTemplate
                        TargetType="Expander">
                        <Border
                            BorderThickness="1">
                            <ContentPresenter />
                        </Border>
                    </ControlTemplate>
                </Expander.Template>
            </Expander>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.Items>
        <StackPanel>
            <TextBlock
                FontSize="14"
                FontWeight="Bold"
                Text="Users:" />
            <wt:DataGrid
                Margin="0,1,0,0"
                AutoGenerateColumns="False"
                CanUserAddRows="True"
                CanUserDeleteRows="True"
                ItemsSource="{Binding Source={StaticResource Main_SystemUsers}, XPath=//Users/*}">
                <wt:DataGrid.Columns>
                    <wt:DataGridTextColumn
                        Header="User Name"
                        Binding="{Binding XPath=@UserName}" />
                    <wt:DataGridComboBoxColumn
                        Header="Role"
                        ItemsSource="{Binding Source={StaticResource Main_UserRoles}, XPath=//Roles/*}"
                        SelectedValueBinding="{Binding XPath=@Role}" />
                </wt:DataGrid.Columns>
            </wt:DataGrid>
            <StackPanel
                Margin="0,10,0,0"
                Orientation="Horizontal">
                <Button
                    Content="Add New User..." />
                <Button
                    Margin="10,0,0,0"
                    Content="Delete User..." />
            </StackPanel>
        </StackPanel>
    </ItemsControl.Items>
</ItemsControl>

Discussion:

The only thing that shows up when I run this is the DataGrid of users and the buttons ("Add New User" and "Delete User") below it. There is no Expander or title bar. Also, even if I did see one, I'm not sure how to set up a Binding for the title that appears on the title bar. I know how to do bindings if I use ItemsSource, but I wanted to set my items declaratively.

The question:

How should I go about this? I'm looking for either a fix for what I have now or a clean-sheet solution.

Edit:

What I ended up doing was replacing the ItemsControl with a StackPanel and just writing a style for my expanders. This proved to be much simpler, and there really was no benefit to the ItemsControl since I needed to declare custom content for each item anyway. The one issue remaining was how to achieve a custom title for each expander. That's where @Thomas Levesque's suggestion to use TemplateBinding came in. All I had to do was replace Text="Title_Of_Expander_Goes_Here" in my header's template (see code above) with Text="{TemplateBinding Content}".

like image 916
devuxer Avatar asked Sep 25 '09 00:09

devuxer


1 Answers

You're not seeing the Expander because you redefined its template. This one should work better :

        ...
        <Expander.Template>
          <ControlTemplate
              TargetType="Expander">
              <Border
                  BorderThickness="1">
                  <Expander Content="{TemplateBinding Content}" Header="{TemplateBinding Header}"/>
              </Border>
          </ControlTemplate>
        </Expander.Template>
        ...
like image 50
Thomas Levesque Avatar answered Oct 15 '22 17:10

Thomas Levesque