2011-09-12 17 views
7

Un TextBlock debe centrarse en una posición x (o y cuando la orientación es vertical). implementé:Cómo centrar un TextBlock en una posición determinada

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 

Esto funciona bien real, pero ¿es posible hacer esto sin UpdateLayout. Si elimino UpdateLayout, no obtengo la posición que estoy buscando, porque ActualWidth es (por supuesto) cero.

+1

que saber que si se utiliza una cuadrícula como de contenedores tendrá que centra inmediatamente ? Además de eso: prueba con LayoutTransform y no RenderTransform – fixagon

+0

¿Cuál es el control de los padres? ¿Cuál es el contexto de este código? – loxxy

+0

@fantasticfix Tengo que usar RenderTransform, porque esto se ejecuta en WPF y Silverlight. SL no conoce LayoutTransform. – Em1

Respuesta

3

Usted puede ser capaz de hacer eso mediante la unión de los valores Canvas.Top/Canvas.Left a TextBlock del ActualWidth/ActualHeight y usando un Converter.

Aquí hay un ejemplo. Estoy usando un MathConverter personalizado que utilizo habitualmente para fórmulas matemáticas (el código se puede encontrar en here), pero también podría usar un convertidor simple que devuelva la mitad del valor que se le pase.

<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}, 
        [email protected]/2}" /> 
     </Trigger> 
     <Trigger Property="Orientation" Value="Vertical"> 
      <Setter Property="Canvas.Top" 
        Value="{Binding RelativeSource={RelativeSource Self}, 
        Path=ActualHeight, 
        Converter={StaticResource MathConverter}, 
        [email protected]/2}" /> 
     </Trigger> 
    </Style.Triggers> 
</Style> 

Editar

Sólo volver a leer la pregunta y se dio cuenta que estamos tratando de centrar el TextBlock en una x específicos, la coordenada y en el lienzo. En ese caso, deberá implementar un MultiConverter en lugar de un Converter regular para que pueda pasarle dos parámetros: el valor X/Y y el valor ActualHeight/ActualWidth

+0

Buena idea. Voy a darle una oportunidad. – Em1

+0

Funciona bien, gracias. – Em1

0

Supongo que escribió este código en el constructor Sería una razón por la cual ActualWidth no tiene ningún valor. Todo el código no se ha probado (no hay IDE disponible). Debe hacer esto después del evento cargado, después de que WPF haya construido el diseño. Este es un evento enrutado, por cierto.

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

Este código probablemente funcione. Por supuesto, por la forma en que leo tu código, este código parece estar situado en el constructor de una clase que derivaste de Canvas. Normalmente no debería haber necesidad de hacerlo, excepto cuando realmente necesite extender la funcionalidad principal del control canvas. Puede crear componentes reutilizables sobre los controles existentes creando un UserControl. Debería usar especialmente este enfoque si no necesita anular ningún método del lienzo.

otra parte, si lo que desea es tener un elemento de centrado dentro de un contenedor, el siguiente XAML lo hará muy bien:

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

No creo que esto funcione, porque creo que es necesario hacer un control antes de que pueda obtener su 'ActualWidth' – Rachel

+0

No constructor. HorizontalAlignment no funciona para mí. – Em1

+0

@ Rachel: Exactamente. Es por eso que debemos tratar de obtener el ancho real después del evento cargado. –

Cuestiones relacionadas