WPFボタンに画像を表示する-文字の上に画像を重ねて表示する

WPFでアプリケーションを開発しています。

操作が完了したら、ボタンの上に完了を意味するアイコンを表示したい(文字の上に重ねて画像を表示したい)という案件が出てきました。

bluebird.pngを表示したいXAML上にドロップすると、ソリューションエクスプローラに表示されます。ソリューションエクスプローラ上で、分かりやすいフォルダを作成し分類しておきます。

bluebird.png
vs01.jpg

ボタンにスタックパネルを作成し、Image Sourceと、Label Contentを配置します。
文字と絵がかさならない状態はこれでできます。

<Window x:Class="ボタンに画像貼り付け.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ボタンに画像貼り付け"
        mc:Ignorable="d"
        Title="MainWindow" Height="227.003" Width="465.31">
    <Grid>
        <Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="254" Height="82" Margin="104,58,99,56">
            <StackPanel Orientation="Horizontal" Margin="4,2">
                <Image Source="./Resources/bluebird.png" VerticalAlignment="Center" />
                <Label Content="ユーザー" VerticalAlignment="Center" Margin="10,0,0,0"/>
            </StackPanel>
        </Button>
    </Grid>
</Window>
vs02.jpg

文字を重ねたい場合は、StackPanelを利用せず、Gridを利用します。

<Window x:Class="ボタンに画像貼り付け.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ボタンに画像貼り付け"
        mc:Ignorable="d"
        Title="MainWindow" Height="227.003" Width="465.31">
    <Grid>
        <Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="254" Height="82" Margin="104,58,99,56">
            <Grid>
                <Image x:Name="image01" Source="./Resources/bluebird.png" VerticalAlignment="Center" />
                <Label Content="ユーザーテクニカテストGoGo" VerticalAlignment="Center" />
            </Grid>
        </Button>
    </Grid>
</Window>
vs03.jpg

後は、C#コード上から、image01のvisiblityをVisibleにするか、Collapseにするかで制御します。

できれば、ボタンは一つの部品として扱いたいです。その中の画像は、そのボタンのプロパティといういか、そのボタンに紐づけて動作して欲しいところ。ボタンがたくさんあるアプリを作る時に、ボタン動作と、その中に表示される画像を別々で管理するのも大変です。

そこで、Contextを利用して、画像のVisibilityを渡す方法を考えました。

Xaml上のボタン名はb01で、その中のGrid上のImageオブジェクトの名前は意識しません。その代り、Imageオブジェクトにバインディングを仕掛けます。Visibility=”{Binding Path=ImageVisibility}

        <Button x:Name="b01" HorizontalAlignment="Center" VerticalAlignment="Center" Width="254" Height="82" Margin="104,10,99,104">
            <Grid>
                <Image x:Name="image02" Source="./Resources/bluebird.png" VerticalAlignment="Center" Visibility="{Binding Path=ImageVisibility}" />
                <Label Content="ユーザーテクニカテストGoGo" VerticalAlignment="Center" />
            </Grid>
        </Button>

このバインディングめがけて、C#コード上からb01のDataContextを利用してVisibilityを引き渡します。

b01.DataContext = new { ImageVisibility = Visibility.Collapsed };

実行した時、まれに画像が表示されない時があります。この場合は、画像ファイルのパスを疑います。今回は画像ファイルをResoucesフォルダに配置したので、パスは、

Source="./Resources/bluebird.png"

このように指定しました。

同じ要領で、画像のパスをDataContextに入れて渡す事も可能です。

Xaml

            <Grid>
                <Image Source="{Binding ButtonImage}" VerticalAlignment="Center" Visibility="{Binding ImageVisibility}" />
                <Label Content="ユーザーテクニカテストGoGo" VerticalAlignment="Center" />
            </Grid>
        </Button>

C#コード

            b01.DataContext = new { ImageVisibility = Visibility.Visible, ButtonImage = "Resources/neko.jpg" };

参考 WPF で ボタン に 画像 を 使用する 方法
参考 [WPF/XAML] リソースから画像を読み込む
参考 第5回 WPFの「データ・バインディング」を理解する (1/3)

結論から、同じ方法でGIFアニメーションをImageに設定して表示できるか確認しましたが、pngやJpegと同じように設定してもアニメーションは再生されない事が分かりました。

ボタンにアニメーションGIFを表示します。WPFでやるならBlendを利用してアニメーションを作るのがスマートだと思うのですが、Formアプリケーションも合わせて手掛けており、部品を共通化したかったのでアニメーションGIFを作りました。

アニメーションGIFは、GIMPを利用する事で簡単に作成できます。

1.レイヤー1枚ごとに1フレーム作成

2.フィルター ⇒ アニメーション ⇒ Gif用最適化

3.各レイヤーの名称レイヤー #3(100ms)(combine) の秒数変更

4.エクスポート

作成したGifアニメーション

GimpでのGIFアニメーション作成は簡単でした。ただ、これをImage Sourceに設定してもGIFアニメーションは再生できませんでした。動かすためには、WPFのImageじゃダメみたいです。

前のコマを表示したくなければGimpからエクスポートする時に

レイヤーごとに1フレーム(置換)

を指定します。

Windows Formアプリケーションなら、Picture Boxを利用して簡単にGIFアニメーションを再生可能です。

後は、このPictureBoxにClickイベントをつけてしまえばアニメーションボタンぽく配置できます。

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("test");
        }

WPFでアニメーションするならわざわざGifを貼り付けなくても素直にBlendでアニメーション作っちゃった方がいいです。めっちゃ便利。