如何将TextBlock置于给定位置的中心位置

时间:2011-09-12 15:48:18

标签: c# wpf silverlight

TextBlock应居中于位置x(或方向为垂直时为y)。 我实施了:

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

这实际上很好,但是可以在没有UpdateLayout的情况下执行此操作。如果我删除UpdateLayout,那么我找不到我想要的位置,因为ActualWidth(当然)为零。

2 个答案:

答案 0 :(得分:3)

您可以通过将Canvas.Top / Canvas.Left值绑定到TextBlock的ActualWidth / ActualHeight并使用Converter来实现此目的。

这是一个例子。我正在使用我通常用于数学公式的自定义MathConverter(代码可以找到here),但您也可以使用普通转换器返回其传递的任何值的一半。

<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>

修改

重新阅读问题并意识到您正试图将TextBlock置于Canvas上特定的x,y坐标中心。在这种情况下,您需要实现MultiConverter而不是常规Converter,以便您可以传递两个参数:X / Y值和ActualHeight / ActualWidth值

答案 1 :(得分:0)

我假设您在构造函数中编写了此代码。这就是为什么ActualWidth没有值的原因。 所有代码尚未经过测试(没有可用的IDE)。在WPF构建布局之后,您需要在Loaded Event之后执行此操作。这是一个路由事件,顺便说一句。

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);
    };
}

此代码可能会有效。当然,在我阅读代码的方式中,这段代码似乎位于您从Canvas派生的类的构造函数中。通常应该没有必要这样做,除非您真的需要扩展canvas控件的核心功能。您可以通过创建UserControl在现有控件之上创建可重用组件。如果您不需要覆盖Canvas的任何方法,则应特别使用此方法。

或者,如果您只想在容器中放置一个居中的项目,那么下面的xaml就可以做到这一点:

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