WPF 標準コントロールデモアプリ › Canvas

Canvas Graphics

Canvas は、添付プロパティ Canvas.Left・Top・Right・Bottom で指定した座標に、子をその子自身の大きさで置くパネルです。

子は自分の大きさのまま置かれる

Canvas は子を測りますが、渡す大きさは無限で、子は Infinity × Infinity で測られました。そのため子は自分の大きさのままです。幅 300 の Canvas で、TextBlock は幅 60.23、HorizontalAlignment="Stretch" の Border も文字の幅の 37.29 のままでした。Canvas の中では配置の指定で子は伸びないので、何かを埋めたい子には大きさを明示します。

Left と Right のどちらが優先されるか

位置を指定しない子は (0, 0) に置かれます。デモアプリの初期値の Canvas.Top 20・Canvas.Left 20 では、四角形 A は (20, 20) に 100 × 100 で置かれ、-30 のような負の Canvas.Left では一部が Canvas の左外に出ました。

Canvas.Right と Canvas.Bottom は、Left と Top に負けます。4 つとも 20 にしても、四角形は (20, 20) の 100 × 100 のままで、動きも伸びもしませんでした。Left と Right はどちらか一方だけを設定します。デモアプリは FallbackValue を NaN にしてバインドしているので、空のテキストボックスでは未設定(NaN)になり、「30」では 30 になります。

Right と Bottom の基準

Right と Bottom の基準は Canvas の実際の大きさなので、Canvas に Width は要りません。Right 20・Bottom 20 だけを設定すると、300 × 200 に広がった Canvas では四角形は (180, 80) に置かれました。隅から決まった距離にバッジを置くときに使えます。大きさ 0 の Canvas では、同じ四角形が (-120, -120) に置かれました。

大きさ 0 の Canvas でも子が表示される理由

Canvas 自身は大きさを求めません。(20, 20) に四角形を置いた Canvas を横の StackPanel に入れると、DesiredSize は 0 × 0 でした。大きさを子に合わせる親の中では領域を得られないので、Canvas の大きさは親か自分の Width・Height で決めます。それでも子が表示されるのは、ClipToBounds の既定値が False だからです。幅 200 の Canvas で 150〜250 に置いた四角形は、Canvas の外の x=230 でもヒットテストに当たりました。デモアプリが設定している ClipToBounds="True" では、そこでは何も当たりませんでした。子を中に収めるなら設定します。

ZIndex

デモアプリの初期値は、四角形 A の ZIndex が 0、B が 1 で、重なった (85, 85) では B が上でした。A を 2 にすると A が上に、両方 0 では後の子の B が上になりました。

条件 計測値
子に渡される大きさ / TextBlock の幅 / Stretch の Border の幅(幅 300 の Canvas) Infinity x Infinity / 60.23 / 37.29
(20, 20) に子を置いた Canvas、横向きの StackPanel の中: DesiredSize / ClipToBounds の既定値 0 x 0 / False
デモの初期値 Top 20、Left 20 x=20 y=20 w=100 h=100
Left 20 と Right 20、Top 20 と Bottom 20(300 x 200 の Canvas) x=20 y=20 w=100 h=100
Right 20 と Bottom 20 だけ、300 x 200 に広げた Canvas(Width の指定なし) x=180 y=80 w=100 h=100
同じ指定で大きさ 0 の Canvas(StackPanel の中) x=-120 y=-120 w=100 h=100
位置の指定なし / Left -30 x=0 y=0 w=100 h=100 / x=-30 y=150 w=100 h=100
幅 200 の Canvas、子を Left 150(250 まで)、ClipToBounds=False: x=230 のヒットテスト A
幅 200 の Canvas、子を Left 150(250 まで)、ClipToBounds=True: x=230 のヒットテスト (なし)
デモの長方形 A (20, 20) と B (50, 50)、ZIndex A=0、B=1: (85, 85) で上にあるもの B
デモの長方形 A (20, 20) と B (50, 50)、ZIndex A=2、B=1: (85, 85) で上にあるもの A
デモの長方形 A (20, 20) と B (50, 50)、ZIndex A=0、B=0: (85, 85) で上にあるもの B
デモの FallbackValue=NaN のバインド: 文字列 "" / "30" のときの Canvas.Right NaN / 30

大きさ、位置、切り抜き、ZIndex。.NET 10 / Windows 11 で計測。

デモアプリで試す

デモアプリの Canvas のページ。左にコントロールの一覧、右に最初の節の Top / Left / Right / Bottom / ZIndex(Panel)

デモアプリの Canvas のページには 1 つの欄があり、100 × 100 の 2 つの四角形があります。四角形 A は Top・Left・Right・Bottom・ZIndex をテキストボックスにバインドし、四角形 B は (50, 50) にあって自分の ZIndex を持っています。欄の下の「Show Code」リンクで、その XAML を表示できます。次の XAML は、結果の部分(CanvasUsageControl.xaml)に、四角形がバインドしているテキストボックスと名前空間の宣言を加えたものです。バインドの TargetNullValue と FallbackValue、スタイル、テキストボックスの入力制限のビヘイビア、GroupBox は省き、周囲のレイアウトは高さ 300 の DockPanel に置き換えています。

<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           Height="300">
  <UniformGrid DockPanel.Dock="Top" Columns="6">
    <TextBox x:Name="TopTextBox" Text="20" />
    <TextBox x:Name="LeftTextBox" Text="20" />
    <TextBox x:Name="RightTextBox" Text="" />
    <TextBox x:Name="BottomTextBox" Text="" />
    <TextBox x:Name="ZIndexTextBox" Text="0" />
    <TextBox x:Name="ZIndexTextBoxRed" Text="1" />
  </UniformGrid>

  <Canvas Background="#F0F0F0" ClipToBounds="True">
    <Rectangle x:Name="TargetRect"
               Canvas.Left="{Binding Text, ElementName=LeftTextBox}"
               Canvas.Top="{Binding Text, ElementName=TopTextBox}"
               Canvas.Right="{Binding Text, ElementName=RightTextBox}"
               Canvas.Bottom="{Binding Text, ElementName=BottomTextBox}"
               Width="100" Height="100"
               Panel.ZIndex="{Binding Text, ElementName=ZIndexTextBox}"
               Fill="SkyBlue" Stroke="DodgerBlue" StrokeThickness="2" />
    <Rectangle Canvas.Left="50" Canvas.Top="50"
               Width="100" Height="100"
               Panel.ZIndex="{Binding Text, ElementName=ZIndexTextBoxRed}"
               Fill="LightCoral" Stroke="IndianRed" StrokeThickness="2" />
  </Canvas>
</DockPanel>

関連するコントロールと記事

ソースコードと計測の方法

このページの挙動の記述は、すべて .NET 10 / Windows 11 で実際に動かして確かめたものです。計測には、このサイトのスクリーンショット生成ツールの CanvasDemoScene を使い、デモアプリと同じ 100 × 100 の四角形で試しました。Canvas は Measure と Arrange でレイアウトし、上にある要素は指定した位置のヒットテストで調べました。大きさは、計測したマシンでの値です。

GitHub で Canvas のソースコードを見る →