2011-09-12 18 views
7

TextBlockの位置は、xの位置に合わせる必要があります(Orientationが垂直の場合はy)。 私が実装さ:TextBlockを指定された位置に配置するには

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は(もちろん)0なので、私が探しているポジションは得られません。

+1

あなたはコンテナとしてグリッドを使用する場合は、それはすぐに集中しているということを知っています?それ以外に、RenderTransformではなくLayoutTransformで試してください – fixagon

+0

親コントロールとは何ですか?このコードのコンテキストは何ですか? – loxxy

+0

@fantasticfixこれはWPFとSilverlightで動作するため、RenderTransformを使用しました。 SLはLayoutTransformを知らない。 – Em1

答えて

3

あなたはのTextBlockのActualWidth/ActualHeightConverterを使用してCanvas.Top/Canvas.Left値を結合することによってそれを行うことができるかもしれません。

例を示します。私は通常、数式(コードはhere)に使用するカスタムMathConverterを使用していますが、渡される値の半分を返すプレーンコンバーターを使用することもできます。

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

編集

ただ、質問を再読み込みして、yはキャンバス上の座標、特定のxでのTextBlockを中央にしようとしている実現。あなたはそれを2つのパラメータを渡すことができるようにそのケースでは、通常のConverterの代わりにMultiConverterを実装する必要があります:X/Y値、およびActualHeight/ActualWidth値を、私はあなたがこのコードを書いたことを前提としてい

+0

良いアイデア。私はそれを試してみましょう。 – Em1

+0

うまく動作します、ありがとうございます。 – Em1

0

コンストラクタActualWidthに値がない理由は、これが原因です。 すべてのコードはテストされていません(IDEは利用できません)。 WPFがレイアウトを構築した後、ロードされたイベントの後でこれを行う必要があります。これはルーティングイベント、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); 
    }; 
} 

このコードはおそらく動作します。もちろん、あなたのコードを読んでいるように、このコードは、あなたがCanvasから派生したクラスのコンストラクタに置かれているようです。キャンバスコントロールのコア機能を本当に拡張する必要がある場合を除いて、通常はそうする必要はありません。 UserControlを作成することで、既存のコントロールの上に再利用可能なコンポーネントを作成できます。キャンバスのメソッドをオーバーライドする必要がない場合は、特にこの方法を使用する必要があります。あなただけのコンテナ内部の中心にアイテムを持っているしたい場合は

また、以下のXAMLはうまくそれを行います。

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

私はあなたが 'ActualWidth'を得る前にコントロールをレンダリングする必要があると信じているので、これはうまくいきません。 – Rachel

+0

コンストラクタではありません。 Horizo​​ntalAlignmentは私のためには機能しません。 – Em1

+0

@レイチェル:まさに。そのため、ロードされたイベントの後に実際の幅を取得しようとする必要があります。 –

関連する問題