2011-09-12 13 views
7

Un TextBlock deve essere centrato in una posizione x (o y quando Orientation è verticale). ho implementato:Come centrare un TextBlock in una data posizione

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 

Questo funziona bene reale, ma è possibile farlo senza UpdateLayout. Se rimuovo UpdateLayout, quindi non ottengo la posizione che sto cercando, perché ActualWidth è (ovviamente) zero.

+1

si sa che se si utilizza una griglia come contenitore si avrà subito centrato ? Accanto a questo: prova con LayoutTransform e non RenderTransform – fixagon

+0

Qual è il controllo genitore ?? Qual è il contesto di questo codice? – loxxy

+0

@fantasticfix Devo usare RenderTransform, perché viene eseguito in WPF e Silverlight. SL non conosce LayoutTransform. – Em1

risposta

3

Potreste essere in grado di farlo legando i valori Canvas.Top/Canvas.Left a quello del TextBlock ActualWidth/ActualHeight e utilizzando un Converter.

Ecco un esempio. Sto usando un custom MathConverter che di solito uso per formule matematiche (il codice può essere trovato here), ma potresti anche usare un convertitore semplice che restituisce metà del valore che viene passato.

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

Modifica

Basta rileggere la questione e si rese conto che si sta cercando di centrare la TextBlock a uno specifico coordinate x, y sulla tela. In tal caso, è necessario implementare un MultiConverter invece di un normale Converter in modo da poter passare due parametri: l'X/valore Y, e il valore ActualHeight/ActualWidth

+0

Buona idea. Farò un tentativo. – Em1

+0

Funziona bene, grazie. – Em1

0

Presumo che hai scritto questo codice in il costruttore. Sarebbe un motivo per cui ActualWidth non ha valore. Tutto il codice non è stato testato (nessun IDE disponibile). È necessario eseguire questa operazione dopo l'Evento caricato, dopo che WPF ha creato il layout. Questo è un evento indirizzato, 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); 
    }; 
} 

Questo codice probabilmente funzionerà. Naturalmente, il modo in cui leggo il tuo codice, questo codice sembra essere situato nel costruttore da una classe derivata da Canvas. Normalmente non dovrebbe esserci bisogno di farlo, tranne quando è veramente necessario estendere la funzionalità di base del controllo canvas. È possibile creare componenti riutilizzabili in aggiunta ai controlli esistenti creando un controllo utente. In particolare, dovresti usare questo approccio se non hai bisogno di sovrascrivere alcun metodo della tela.

In alternativa, se si vogliono solo avere una voce centrato all'interno di un contenitore, il seguente XAML farà che bene:

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

Non penso che funzionerà perché credo che sia necessario eseguire il rendering di un controllo prima di poter ottenere il valore di 'ActualWidth' – Rachel

+0

Non costruttore. HorizontalAlignment non funziona per me. – Em1

+0

@ Rachel: Esattamente. Ecco perché dovremmo cercare di ottenere la larghezza effettiva dopo l'evento caricato. –

Problemi correlati