简体   繁体   中英

How do I center a TextBlock to a given position

A TextBlock should be centered to a position x (or y when Orientation is vertical). I implemented:

TextBlock text = new TextBlock();
// Some code to define text, font, etc. here

// Turn if Orientation is vertical
if (Orientation == Orientation.Vertical) 
{
  text.RenderTransform = new RotateTransform() { Angle = 270 };
}

// Update, then ActualWidth is set correctly
text.UpdateLayout();

// Position of label centered to given position
double halfWidth = text.ActualWidth / 2;
double x1 = (Orientation == Orientation.Horizontal) ? x - halfWidth : x;
double y1 = (Orientation == Orientation.Horizontal) ? y : y + halfWidth;

Canvas.SetLeft(text, x1);
Canvas.SetTop(text, y1);

Children.Add(text); // Add to Canvas

This works actual fine, but is it possible to do this without UpdateLayout . If I remove UpdateLayout , then I do not get the position I am looking for, because ActualWidth is (of course) zero.

You might be able to do that by binding the Canvas.Top / Canvas.Left values to the TextBlock's ActualWidth / ActualHeight and using a Converter .

Here's an example. I'm using a custom MathConverter that I usually use for mathematical formulas (code can be found here ), but you could also use a plain converter that returns half of whatever value it gets passed.

<Style TargetType="{x:Type TextBlock}">
    <Style.Triggers>
        <Trigger Property="Orientation" Value="Horizontal">
            <Setter Property="Canvas.Left" 
                    Value="{Binding RelativeSource={RelativeSource Self}, 
                    Path=ActualWidth,
                    Converter={StaticResource MathConverter}, 
                    ConverterParameter=@VALUE/2}" />
        </Trigger>
        <Trigger Property="Orientation" Value="Vertical">
            <Setter Property="Canvas.Top" 
                    Value="{Binding RelativeSource={RelativeSource Self}, 
                    Path=ActualHeight,
                    Converter={StaticResource MathConverter}, 
                    ConverterParameter=@VALUE/2}" />
        </Trigger>
    </Style.Triggers>
</Style>

Edit

Just re-read the question and realized you're trying to center the TextBlock at a specific x,y coordinate on the Canvas. In that case, you'll need to implement a MultiConverter instead of a regular Converter so that you can pass it two parameters: the X/Y value, and the ActualHeight/ActualWidth value

I assume that you wrote this code in the constructor. It would be a reason why ActualWidth has no value. All the code hasn't been tested (no IDE available). You need to do this after the Loaded Event, after WPF has built the layout. This is a routed event, btw.

public class Class1{
public Class1 ()
{
    this.Loaded += (sender, args) =>
    {
        TextBlock text = new TextBlock();

        if (Orientation == Orientation.Vertical) 
        {
          text.RenderTransform = new RotateTransform() { Angle = 270 };
        }

        double halfWidth = text.ActualWidth / 2;
        double x1 = (Orientation == Orientation.Horizontal) ? x - halfWidth : x;
        double y1 = (Orientation == Orientation.Horizontal) ? y : y + halfWidth;

        Canvas.SetLeft(text, x1);
        Canvas.SetTop(text, y1);
        Children.Add(text);
    };
}

This code will probably work. Of course, the way I read your code, this code seems to be situated in the constructor from a class that you derived from Canvas. There should normally be no need to do so, except when you really need to extend the core functionality of the canvas control. You can make reusable components on top of existing controls by creating a UserControl. You should especially use this approach if you don't need to override any method of the Canvas.

Alternatively, if you just want to have a centered item inside a container, the following xaml will do that just fine:

     <Grid>
        <TextBlock Text="Haha!" VerticalAlignment="Center" HorizontalAlignment="Center"/>
     </Grid>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM