Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aligning Text with a ContentControl using the HorizontalContentAlignment property

I am attempting to apply a "text alignment" to a ContentControl. Since the ContentControl does not have a horizontal or vertical text alignment property like the TextBlock, I am attempting to use the ContentControl's HorizontalContentAlignment property.

My problem is that I can't get it to work with a ContentControl itself.

In my example, I have a content control displaying "hello world" and a button displaying "change it".

When I click the button, I set the HorizontalContentAlignment on the content control and on the button. The button's content changes, but the content control's content does not.

Here is my XAML code:

<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <ContentControl x:Name="ctrl" Width="525">
        Hello World!
    </ContentControl>
    <Button x:Name="btn" Grid.Row="1" Content="Change It" Click="btn_Click"/>
</Grid>
</Window>

And here is my VB.NET code for the button click event:

Class MainWindow 

  Private Sub btn_Click(sender As System.Object, e As System.Windows.RoutedEventArgs)
    If (ctrl.HorizontalContentAlignment = HorizontalAlignment.Left) Then
        ctrl.HorizontalContentAlignment = HorizontalAlignment.Right
        btn.HorizontalContentAlignment = Windows.HorizontalAlignment.Right
    Else
        ctrl.HorizontalContentAlignment = HorizontalAlignment.Left
        btn.HorizontalContentAlignment = Windows.HorizontalAlignment.Left
    End If
    ctrl.UpdateLayout()
  End Sub

End Class

I am unable to replace my content controls with text blocks for various reasons, but I still need to be able to align the content.

EDIT:

While Narohi work around suggestion works, I am still confused about why the content control's HorizontalContentAlignment property doesn't align the content.

I tried a Label control (which inherits from ContentControl) and it's HorizontalContentAlignment property properly aligns the content.

(Edit again: I am no longer confused about this, it seems that the HorizontalContentAlignment isn't utilized properly in all cases.)

Here is my updated XAML code:

<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <ControlTemplate x:Key="AlignmentAwareControl" TargetType="ContentControl">
            <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
    </ControlTemplate>
</Window.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <ContentControl x:Name="ctrlTxt" Grid.Row="0"
                    Template="{StaticResource AlignmentAwareControl}" 
                    HorizontalContentAlignment="Center" Padding="0">Hello World Content Control!</ContentControl>
    <Label x:Name="ctrl" Grid.Row="1"  HorizontalContentAlignment="Center" Padding="0">Hello World Label!</Label>
    <ContentControl x:Name="ctrlImg" Grid.Row="2" 
                    Template="{StaticResource AlignmentAwareControl}"
                    HorizontalContentAlignment="Center">
        <Image Source="C:\Users\Frinavale\Pictures\Business_Woman.jpg"/>
    </ContentControl>

    <Button x:Name="btn" Grid.Row="3" Content="Change It" Click="btn_Click"/>
</Grid>
</Window>

Here is my updated VB.NET code:

Class MainWindow 

  Private Sub btn_Click(sender As System.Object, e As System.Windows.RoutedEventArgs)
    If (ctrl.HorizontalContentAlignment = HorizontalAlignment.Left) Then
        ctrlImg.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Right)
        ctrlTxt.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Right)
        ctrl.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Right)
        btn.HorizontalContentAlignment = Windows.HorizontalAlignment.Right
    Else
        ctrlImg.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Left)
        ctrlTxt.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Left)
        ctrl.SetValue(ContentControl.HorizontalContentAlignmentProperty, Windows.HorizontalAlignment.Left)
        btn.HorizontalContentAlignment = Windows.HorizontalAlignment.Left
    End If
    ctrl.UpdateLayout()
  End Sub
End Class

I'm looking forward to your advice,

-Frinny

like image 616
Frinavale Avatar asked Feb 19 '13 20:02

Frinavale


1 Answers

Opening up the default control template for ContentControl in Blend reveals why your original approach did not work.

<ControlTemplate TargetType="{x:Type ContentControl}">
    <ContentPresenter/>
</ControlTemplate>

The default template does nothing with the HorizontalContentAlignment property which it inherited from Control. Juxtapose this with Label's default template.

<ControlTemplate TargetType="{x:Type Label}">
    <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
    </Border>
    <ControlTemplate.Triggers>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

As we can see, the Label actually binds to the HorizontalContentAlignment. WPF controls are lookless, so there is never a guarantee that a property will be respected by the current ControlTemplate. I would speculate that the WPF designers didn't respect the HorizontalContentAlignment property because people usually place content within that is independent of the ContentControl's properties or perhaps they assumed if someone was going to use such a generic control they would provide their own template, such as...

<ContentControl x:Name="ctrl" Width="525">
    <ContentControl.Template>
        <ControlTemplate TargetType="ContentControl">
            <Grid>
                <ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
            </Grid>
        </ControlTemplate>
    </ContentControl.Template>
    Hello World!
</ContentControl>
like image 91
Nathan Hillyer Avatar answered Sep 27 '22 03:09

Nathan Hillyer