【解決】OpacityMaskにResourcesが反映されない!

WPFで、OpacityMaskとResourcesの挙動に散々悩まされた。

同じような症状に悩まされてる人の参考になればと思って記事にする。

目次

まずはOpacityMaskを使ってみる。

以下のようなオレンジの画像を用意した。

背景が透明になっているので、OpacityMaskとしても使える

<!--画像として使う-->
<img source="Resources\orange.png">
 
<!--OpacityMaskとして使う-->
<rectangle grid.column="1">
    <rectangle.opacitymask>
        <imagebrush imagesource="Resources\orange.png">
    </imagebrush></rectangle.opacitymask>
    <rectangle.fill>
        <solidcolorbrush color="Blue">
    </solidcolorbrush></rectangle.fill>
</rectangle>

実行してみるとこんな感じ。

左には画像が表示され、右には青いRectangleが画像のアルファ値で切り抜かれたものが表示された。

なんの問題もない。

Resource.resxで指定してみる。

Resourceを用意する。

保持する内容は画像のパスだ。

ResourceをXamlで指定して…

<!--画像として使う-->
<img source="{Binding Source={x:Static properties:Resources.OrangeImg}}">
 
<!--OpacityMaskとして使う-->
<rectangle grid.column="1">
    <rectangle.opacitymask>
        <imagebrush imagesource="{Binding Source={x:Static properties:Resources.OrangeImg}}" stretch="Uniform">
    </imagebrush></rectangle.opacitymask>
    <rectangle.fill>
        <solidcolorbrush color="Blue">
    </solidcolorbrush></rectangle.fill>
</rectangle>

できた!完璧!実行!!

……

???????????

どうして動いてくれないんですか?

Imageにはきちんと反映されてるいるがOpacityMaskが動いていない。

出力のエラーメッセージを見てみる。

System.Windows.Data Error: 6 :
'TargetDefaultValueConverter' converter failed to convert value
'Resources\orange.png' (type 'String'); fallback value will be used,
if available. BindingExpression:Path=; DataItem='String' (HashCode=-128968901); 
target element is 'ImageBrush' (HashCode=23240469); 
target property is 'ImageSource' (type 'ImageSource')
IOException:'System.IO.IOException: リソース 'resources/orange.png' を検索できません。

きちんと「Resources/orange.png」が取得できてる。

なのにIOExceptionが出ている。

Imageのほうはきちんと動いてるじゃん。

さっきXAMLに直書きした時は動いてたじゃん。

どうして…どうして…

原因(?)と解決

原因はディレクトリ構造にあった。

MainWindow.xmlから見るとResourceフォルダは同じ階層にあるが、

PropertiesからみるとResourceフォルダの間にViewsフォルダがある。

まさかと思ってViewを跨いだパスをResourceで保持して

それを指定すると

<!--画像として使う-->
<Image Source="{Binding Source={x:Static properties:Resources.OrangeImg}}"&amp;gt;
 
<!--OpacityMaskとして使う-->
<Rectangle Grid.Column="1">
    <Rectangle.OpacityMask>
        <!--「OrangeImg」を「OrangeOM」に変更-->
        <ImageBrush ImageSource="{Binding Source={x:Static properties:Resources.OrangeOM}}"
           Stretch="Uniform">
    </Rectangle.OpacityMask>
    <Rectangle.Fill>
        <SolidColorBrush Color="Blue"&amp;gt;
    </Rectangle.Fill>
</Rectangle>

きちんと動いた。どうして。

Imageコントロールのほうでは動いてるのにOpacityMaskでは動かないのが不可解だ。

「ImageコントロールのSource」と「ImageBrushのImageSource」の挙動の違いだとは思うけれども

例外的な挙動をするのはやめてほしい。