Right-align items within wpf expander header

I want to have some text in an expander header left aligned, then some text right aligned. I have found how to expand the header to the width of the container, and thought I could simply add a dockpanel and set the second text block to Dock Right, but it doesn't seem to help. Any solutions?

<Expander>
  <Expander.Header>
    <DockPanel
      Width="{Binding
        RelativeSource={RelativeSource
        Mode=FindAncestor,
        AncestorType={x:Type Expander}},
        Path=ActualWidth}">
      <TextBlock
        Text="I am header text…"
        Background="LightBlue"
      />
      <TextBlock DockPanel.Dock="Right"
        Text="I am header text…"
        Background="Yellow"
      />
    </DockPanel>
  </Expander.Header>
</Expander>

Solution 1:

This is what worked for me. This also moves the arrow to the right, because it's reverting the order of the header and re-reverting the order for the content.

<Expander FlowDirection="RightToLeft" >  
  <Expander.Header>
    <DockPanel FlowDirection="LeftToRight" 
          HorizontalAlignment="{Binding HorizontalAlignment,
                          RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}},
                          Mode=OneWayToSource}"
          LastChildFill="True">
      <!-- Change the look inside header here -->

      <Label Content="Header" Background="Red" />
    </DockPanel>
  </Expander.Header>

  <Expander.Content>
    <!-- Change the look inside content here, by default Expander.Content is stretched -->
    <DockPanel FlowDirection="LeftToRight" LastChildFill="True">
      <Label Content="Left" Background="Aquamarine" />
      <Label Content="Fill" Background="Plum" />
    </DockPanel>
  </Expander.Content>
</Expander>

(Source)

Solution 2:

Try setting the TextAlignment property to right and the HorizontalAlignment property to stretch on the TextBlocks. That should help i think.

If your use of color is for something other than demo purposes and you literally want the whole element to be right aligned then you might want to look at setting the LastChildFill property of the DockPanel to false.

Solution 3:

Unfortunately, this has to do with an issue with the default expander template, which sets the horizontal alignment of the header to left instead of stretch. The best way to get it working would be to create a new template that sets this correctly. Here's a link for more info:

http://silverlight.net/forums/p/57142/145801.aspx#145801

it's for silverlight, but applies to wpf as well. Another way to do this would be to bind your dockpanel width above to the actual width of the element containing the expander. This isn't a great solution but it works. You'll need to create a value converter for the width. Here's some code:

[ValueConversion(typeof(double), typeof(double))]
public class OffsetDoubleConverter : IValueConverter
{
    #region IValueConverter Members

    public double Offset { get; set; }
    public bool KeepPositive { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double number = (double)value + Offset;
        if ((KeepPositive) && (number < 0.0))
        {
            number = 0.0;
        }
        return number;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double number = (double)value - Offset;
        if ((KeepPositive) && (number < 0.0))
        {
            number = 0.0;
        }
        return number;
    }

    #endregion
}

And in your xaml:

<!-- create a ref to your namespace -->
xmlns:loc="clr-namespace:YourNamespace"

...

<Window.Resources>
<loc:OffsetDoubleConverter x:Key="ExpanderConverter" Offset="-208.0" KeepPositive="True"/>
</Window.Resources>

...

<DockPanel Width="{Binding ElementName=ADifferentElement, Path=ActualWidth,
                   Converter={StaticResource ExpanderConverter}}">
...

Again, this isn't the best solution, but it should work. One thing to note, if you set the offset value too small and bind it to a parent of your expander, you can get visual studio to hang since the actualwidth of the parent would be based on your width of the expander.

Let me know if this implementation isn't quite clear. Again, I would really recommend just using a custom template for the expander. You can get the default template and just slightly modify it to make it work. I can post that as well if you'd like.