views:

440

answers:

1

I have a custom Expander control called SpecialExpander. It is basically just a standard Expander with a fancy header and a couple properties (HeaderText and IsMarkedRead).

I began by creating a simple class:

public class SpecialExpander : Expander
{
    public string HeaderText { get; set; }
    public bool IsMarkedRead { get; set; }
}

Then I created a style that sets a couple properties on the expander (e.g., margins, padding, etc.) and, importantly, it also defines a custom DataTemplate for the HeaderTemplate property. The template is basically a grid with two rows.

As shown in the illustrations below...

  • for the top row, I'd like a fixed layout (it's always TextBlock TextBlock CheckBox)
  • for the bottom row, however, I want to be able to provide custom XAML for each expander.

I tried putting <ContentControl Grid.Row="1" ... /> in the DataTemplate, but I couldn't figure out how to hook it up properly.


alt text


alt text


Question

How can I build a DataTemplate for my SpecialExpander so that the header has some fixed content (top row) and a place-holder for custom content (bottom row)?

For the second illustration, I would want to be able to do something like this:

<SpecialExpander HeaderText="<Expander Header Text>" IsMarkedRead="True">
    <SpecialExpander.Header>
        <StackPanel Orientation="Horizontal">
            <RadioButton Content="High" />
            <RadioButton Content="Med" />
            <RadioButton Content="Low" />
        </StackPanel>
    <SpecialExpander.Header>
    <Grid>
        <Label>Main Content Goes Here</Label>
    </Grid>
</SpecialExpander>
+1  A: 

It hit me this morning how to solve this: instead of building a SpecialExpander, I just need a normal Expander. Then, for the header, I will use a custom ContentControl called SpecialExpanderHeader.

Here's how it works...

SpecialExpanderHeader class:

public class SpecialExpanderHeader : ContentControl
{
    public string HeaderText { get; set; }
    public bool IsMarkedRead { get; set; }
}

SpecialExpanderHeader style:

<Style TargetType="custom:SpecialExpanderHeader">
    <Setter Property="Padding" Value="10" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="custom:SpecialExpanderHeader">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="5" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <StackPanel Grid.Row="0" Orientation="Horizontal">
                        <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=custom:SpecialExpanderHeader}, Path=HeaderText}" />
                        <CheckBox Margin="100,0,0,0" IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=custom:SpecialExpanderHeader}, Path=IsMarkedRead}" />
                    </StackPanel>
                    <Separator Grid.Row="1" />
                    <ContentPresenter Grid.Row="2" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Expander style

<Style x:Key="Local_ExpanderStyle" TargetType="Expander" BasedOn="{StaticResource {x:Type Expander}}">
    <Setter Property="Margin" Value="0,0,0,10" />
    <Setter Property="Padding" Value="10" />
    <Setter Property="FontSize" Value="12" />
</Style>

Usage

<Expander Style="{StaticResource Local_ExpanderStyle}">
    <Expander.Header>
        <custom:SpecialExpanderHeader IsMarkedRead="True" HeaderText="Test">
            <StackPanel Orientation="Horizontal">
                <RadioButton Content="High" />
                <RadioButton Content="Medium" />
                <RadioButton Content="Low" />
            </StackPanel>
        </custom:SpecialExpanderHeader>
    </Expander.Header>
    <Grid>
        <!-- main expander content goes here -->
    </Grid>
</Expander>
DanM
I love it when that happens :)
Alastair Pitts