.NET MAUI BorderのShadowでXC0009エラーになる原因と解決策|XAMLの正しい指定方法

.NET MAUIのBorderにShadowを付けようとしてXC0009が出るときは、多くの場合「Shadowプロパティはあるのに値の指定方法が型と合っていない」ことが原因です。本記事では、Visual Studio 2022 / .NET 9環境で起きやすいパターンを再現しつつ、Border.ShadowにShadowオブジェクトを正しく設定して解決する手順と、見えない・効かないときのチェック項目までまとめます。

目次

発生する症状:IntelliSenseでは認識するのにXC0009で止まる

Visual Studioの入力補完(IntelliSense)ではShadowが候補に出てくるのに、実行時またはビルド時に次のようなエラーでアプリが起動しない/XAMLコンパイルが通らない、というケースがあります。

XC0009: No property, BindableProperty, or event found for 'Shadow' or mismatching type between value and property

この文面は「Shadowというプロパティがない」もしくは「指定した値とプロパティの型が合っていない」を意味します。Border自体にShadowが存在しないのではなく、実際には後者(型不一致)であることがほとんどです。

結論:Shadowは“数値”ではなく“Shadowオブジェクト”として設定する

Borderの影は、Shadow="20"のように数値だけを渡して作るものではありません。<Border.Shadow>の中に<Shadow />を作り、Brush(影の色)やOffset(ずらし)、Radius(ぼかし)などを指定します。

正しい書き方(そのまま動く例)

まずは“動く最小の型”として、次の形を覚えるのが近道です。

<Border StrokeThickness="2"
        Stroke="Green"
        BackgroundColor="AliceBlue"
        Padding="20">


<Border.Shadow>
    <Shadow Brush="Black"
            Offset="20,20"
            Radius="40"
            Opacity="0.8" />
</Border.Shadow>

<Border.StrokeShape>
    <RoundRectangle CornerRadius="15" />
</Border.StrokeShape>


なぜShadow="20"のような指定でXC0009になるのか

XAMLの属性(Shadow="...")で指定した値は、最初は文字列として解釈されます。XAMLコンパイラは、対象プロパティの型へ変換するために「型変換(TypeConverter)」や既定のパーサーを探します。

しかしBorderのShadowは、厚み(Thickness)や単一の数値ではなく、影を表す複合オブジェクトです。数値だけでは「影の色は? ずらし量は? ぼかしは?」が決められず、XAMLコンパイラはShadow型へ変換できません。その結果、XC0009の“mismatching type between value and property(型が合っていない)”として扱われます。

よくある“間違った例”

次のように書いてしまうと、見た目はそれっぽくても型変換ができずエラーになりやすいです。

<!-- NG例:Shadowは数値ではない -->
<Border Shadow="20" />


Border.Shadowで指定できる主なプロパティと“役割”

Shadowは「影の色」「どれだけずらすか」「どれだけぼかすか」「どれだけ薄くするか」をセットで持ちます。値の意味を理解しておくと、UI調整が格段に楽になります。

プロパティ役割例調整のコツ
Brush影の色(ブラシ)Brush="Black" / Brush="#80000000"真っ黒だと重く見えるので、まずは半透明(例:#66000000)から始めると破綻しにくい
Offset影の位置ずらし(X,Y)Offset="6,10"大きくすると“浮いている感”は出るが、コンテナからはみ出しやすい。まずは小さめで
Radiusぼかし半径Radius="12"小さすぎると硬い影になり、UIが古く見えやすい。角丸が強いほど少し大きめが自然
Opacity不透明度(0〜1)Opacity="0.35"“色を薄くする”より“Opacityを下げる”ほうが、色味を保ったまま軽くできる

実務で使いやすいShadow設定例

「とりあえず影を出す」だけだと、濃すぎたり、ずれすぎたり、プラットフォーム差で違和感が出たりします。ここでは実務で扱いやすい方向性の例をいくつか載せます。

控えめで汎用的なカード風

<Border BackgroundColor="White"
        Padding="16">


<Border.Shadow>
    <Shadow Brush="#66000000" Offset="0,6" Radius="14" Opacity="1" />
</Border.Shadow>

<Border.StrokeShape>
    <RoundRectangle CornerRadius="12" />
</Border.StrokeShape>

<Label Text="Card" />


Brush側を半透明にしておくと、Opacityを1にしても“軽い影”になりやすく、あとから調整するときも色の管理がしやすいです。

右下方向に“浮き”を強めたい場合

<Border BackgroundColor="White"
        Padding="20">


<Border.Shadow>
    <Shadow Brush="#55000000" Offset="10,14" Radius="22" Opacity="1" />
</Border.Shadow>

<Border.StrokeShape>
    <RoundRectangle CornerRadius="16" />
</Border.StrokeShape>

<Label Text="Floating" />


Offsetを大きくするほど、影がコンテナ外にはみ出しやすくなります。レイアウトの都合で影が切れる場合は後述の「クリップ」の項目も確認してください。

Styleで再利用する:Shadowを毎回書かないためのパターン

アプリ全体でカードUIを使うなら、ShadowはStyle化しておくとメンテナンスが楽です。ポイントは、Setterで複合オブジェクトを渡すときは<Setter.Value>を使うことです。

<ResourceDictionary>

  <Style x:Key="CardBorderStyle" TargetType="Border">
    <Setter Property="BackgroundColor" Value="White" />
    <Setter Property="Padding" Value="16" />

    <Setter Property="StrokeShape">
      <Setter.Value>
        <RoundRectangle CornerRadius="12" />
      </Setter.Value>
    </Setter>

    <Setter Property="Shadow">
      <Setter.Value>
        <Shadow Brush="#66000000" Offset="0,6" Radius="14" Opacity="1" />
      </Setter.Value>
    </Setter>
  </Style>

</ResourceDictionary>

使う側はシンプルになります。

<Border Style="{StaticResource CardBorderStyle}">
  <Label Text="Styled card" />
</Border>

テーマ(ライト/ダーク)でShadowを切り替える例

影は背景色の影響を受けやすく、ライトテーマとダークテーマで同じ値を使うと「ライトではちょうど良いのに、ダークでは濃すぎる/逆に見えない」ということが起きます。アプリがAppThemeを使っているなら、ShadowのBrushやOpacityをテーマで切り替えるのがおすすめです。

<Border>
  <Border.Shadow>
    <Shadow Offset="0,6" Radius="14"
            Brush="{AppThemeBinding Light=#66000000, Dark=#99000000}"
            Opacity="{AppThemeBinding Light=1, Dark=0.6}" />
  </Border.Shadow>
</Border>

“Brushを半透明にする”のか“Opacityを下げる”のかは好みですが、テーマで切り替える場合はどちらかに寄せておくとデザイン管理がシンプルになります。

C#側で設定する場合の例

XAMLではなくC#で動的に組み立てたい場合も、結局やることは同じで、Border.Shadowにnew Shadow()を渡します。

var border = new Border
{
    BackgroundColor = Colors.White,
    Padding = 16,
    StrokeShape = new RoundRectangle { CornerRadius = 12 },
    Shadow = new Shadow
    {
        Brush = new SolidColorBrush(Colors.Black),
        Offset = new Point(6, 10),
        Radius = 14,
        Opacity = 0.35f
    }
};

「XAMLだと書き方を間違えやすい」「テーマ切り替えで影の色を切り替えたい」といった要件があるなら、C#側でShadowを生成して差し替える設計も有効です。

Shadowが“効かない・見えない”ときのチェックリスト

型不一致(XC0009)を直しても、影が見えないことがあります。影は描画上の制約を受けやすいので、次の点を順番に確認すると切り分けが早いです。

症状ありがちな原因対処のヒント
影がまったく出ないOffset/Radius/Opacityが弱すぎる、またはBrushが透明に近いまずはBrush="#66000000"、Offset="0,6"、Radius="14"程度の“強め設定”で出るか確認してから弱める。Brushを省略している場合は明示的に指定する
影が途中で切れる親要素がクリップしている(はみ出した部分を切り取っている)レイアウトのIsClippedToBounds(または同等のクリップ設定)を見直し、必要なら余白(Margin)も確保する
角丸と影が合わず不自然CornerRadiusが大きいのにRadiusが小さい角丸が強いほど影のぼかし(Radius)も少し大きめにすると自然。逆に角がシャープならRadiusも控えめでOK
プラットフォームで見え方が違う影の実装がプラットフォームごとに異なる同じ値でも濃さや広がりが変わることがあるため、最終調整はターゲット端末で行う。必要なら条件分岐(OnPlatform)も検討

親レイアウトの“クリップ”が原因になりやすい例

影は要素の外側にはみ出して描画されます。そのため、親レイアウトが「子要素を枠内に収める(クリップする)」設定になっていると、影だけ切れてしまいます。特にスクロールコンテナやテンプレートの内側で起きると気づきにくいので注意してください。

影が切れるときは、次のような“余白不足”もセットで起きがちです。レイアウトが詰まっている場合は、影のためのスペース(Margin)を確保するのも有効です。

<Border Margin="0,0,0,12">
  ...
</Border>

IntelliSenseが通るのにビルドが落ちる理由

入力補完は「そのプロパティ名が存在するか」「候補の一覧として提示できるか」を中心に動きます。一方、XAMLコンパイル(XamlC)は、実際にプロパティへ値を割り当てられるか(型変換できるか)まで検証します。

そのため、プロパティ名は正しいのに値の書き方が不正というケースは、IntelliSenseでは気づけず、ビルド/実行時に初めてXC0009として表面化します。今回のShadowはまさにその典型で、「数値を渡せば影の強さになるはず」という先入観があるとハマりやすいポイントです。

FrameのHasShadowから移行するときの考え方

以前はカードUIにFrameを使い、HasShadowで影を付けるパターンが定番でした。BorderのShadowは、色やぼかし、ずらしを細かく制御できる一方で、設定を“オブジェクトとして書く”必要があります。移行時は次の対応関係を押さえると混乱しません。

やりたいことFrameでの考え方Borderでの考え方
影を付ける/外すHasShadowのオン/オフBorder.Shadowを設定する/未設定にする
影の濃さを調整細かい調整が難しいことが多いBrush(半透明)やOpacityでコントロールする
影の方向や広がりコントロール依存OffsetとRadiusで意図を明確にする

よくある質問

ShadowをBindingで動的に変えたい場合は?

RadiusやOpacityのような単純な数値はBindingしやすいですが、Shadow全体を差し替えたい場合は、ViewModel側でShadowオブジェクトを持つ(または値が変わったらコード側で組み直す)ほうが安定します。XAML上で無理に文字列から組み立てようとすると、今回と同じ“型変換”の壁にぶつかりやすいからです。

Shadowを付けたらタップ判定がずれたり大きくなったりする?

通常、影は描画上の効果であり、レイアウトサイズやタップ領域そのものを増やすものではありません。ただし、影が切れないようにMarginを増やした場合は、要素の占有スペースが増えるため、結果としてレイアウトの当たり判定が変わったように見えることがあります。

XC0009がShadow以外でも出るときは?

XC0009はShadowに限らず「プロパティ名が解決できない」「型が合わない」全般で出ます。対処の基本は同じで、プロパティの型を確認して、XAMLでの指定方法(属性でいけるのか、プロパティ要素が必要なのか)を切り替えることです。複合オブジェクト系のプロパティほど、プロパティ要素で書くほうが事故りにくいです。

影をデザインとして破綻させないための実践的な考え方

最後に、影を付けたあとの“見た目の品質”を上げるための考え方をまとめます。単に影が出るだけで満足せず、UIとして自然に見えるところまで持っていくと、アプリ全体の印象が大きく変わります。

  • 影の色は黒固定にしない:黒だと重い。半透明の黒(#33〜#66)や、背景に合わせた僅かな色味を検討する
  • Offsetを大きくしすぎない:影のズレが大きいほど“浮遊感”は増すが、切れ・違和感も増える。まずは小さく
  • 角丸とRadiusをセットで調整:角が丸いのに影が硬いとチグハグになる。カードUIなら少しぼかす
  • 余白(Margin/Padding)も影の一部:影が見えるスペースがないと、どれだけ正しく書いても切れてしまう

この問題の要点

Borderに影を付けたいのにXC0009が出る場合は、ほぼ確実に「Shadowプロパティへの値の渡し方」が原因です。Border.ShadowにShadowオブジェクトをプロパティ要素で設定するだけで解決し、あとはBrush・Offset・Radius・Opacityを調整して見た目を整えていきます。

まずは本記事の“動く例”をコピペして動作確認し、次にStyle化して再利用、最後にプラットフォーム差やクリップを踏まえた微調整、という順で進めると迷いません。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次