How can I make an “Accordion Widget” in WPF?

2019-02-07 09:28发布

The goal:

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

Widget with several vertically stacked expanders http://wordpress.org/extend/plugins/tabbed-widgets/screenshot-3.png


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}".

2条回答
We Are One
2楼-- · 2019-02-07 09:42

Personally I think a TreeView control would give you a much better base to work from, especially if you're using Expression Blend as a basis to create new/blank Templates from for items. Seeing the default Templates is extremely enlightening and gives you much more fine-grained control and better understanding and insight into how things work by default. Then you can go to town on them. It also looks like you're working with Hierchical Data and TreeViews inherently lend themselves well to working with such data.

查看更多
叛逆
3楼-- · 2019-02-07 09:58

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>
        ...
查看更多
登录 后发表回答