[WinRT] 自動的に閉じるダイアログを作る

モーダルダイアログ風なものができたので、これを応用して自動的に閉じるダイアログを作ります。

のようにメッセージを表示して、しばらくしたら閉じるっていうメッセージダイアログです。よくゲームであるパターンだし、他のアプリでも応用が利きます。
フォームアプリの場合にはタイマーを使ってイベント待ちをするのが定番ですが、WinRT の場合(というか XAMLの場合)には、storyboard を使って、3秒後の閉じる、ってのがコード的に楽です。

自動的に閉じるダイアログは、Popup でも Canvas でもいいのですが、ここでは、popup を使って実現してみます。

■popup でダイアログを作る

popup コントロールを使って、ダイアログを作成。

<Popup x:Name="popYaku" 
        Margin="320,160,-320,328" Grid.Row="1">
    <Grid Background="Red" Height="213" Width="399">
        <TextBlock 
            x:Name="popYakuText"
            FontSize="40"
            HorizontalAlignment="Left" Margin="34,32,0,0" TextWrapping="Wrap" Text="役ができました" VerticalAlignment="Top"/>
        <Image x:Name="pictYaku1" HorizontalAlignment="Left" Height="100" Margin="34,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>
        <Image x:Name="pictYaku2" HorizontalAlignment="Left" Height="100" Margin="103,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>
        <Image x:Name="pictYaku3" HorizontalAlignment="Left" Height="100" Margin="172,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>
        <Image x:Name="pictYaku4" HorizontalAlignment="Left" Height="100" Margin="241,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>
        <Image x:Name="pictYaku5" HorizontalAlignment="Left" Height="100" Margin="310,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>
    </Grid>
</Popup>

この場合には、花札の役を表示するので、あらかじめ image コントロールを貼り付けておきます。

■blend で storyboard を追加する

3秒経ったらダイアログを閉じるタイムラインを、blend を使って作ります。

<Page.Resources>
    <!-- TODO: Delete this line if the key AppName is declared in App.xaml -->
    <x:String x:Key="AppName">花札 こいこい</x:String>
    <Storyboard x:Name="sbPopYaku">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="popYaku">
        	<EasingDoubleKeyFrame KeyTime="0:0:2.5" Value="1"/>
        	<EasingDoubleKeyFrame KeyTime="0:0:3" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Page.Resources>

プログラムから storyboard を起動するので名前をつけておくのと、単に消えると WinRT らしくないので、最後の 0.5 秒だけは透明度を変更するという方式にします。この手のアニメーションは blend を使うとひじょうに楽ですね。

■アニメーション終了時の処理を追加

ポップアップを開くときは、IsOpen プロパティを true にすれば ok。ストリーボードの開始は sbPopYaku.Begin() な感じで実行ができます。
で、忘れちゃいけないのが、アニメーションが終了した時に、ストリーボードを Stop で終了させておくことと、ポップアップを IsOpen = false で閉じておくこと。

/// <summary>
/// 役を表示
/// </summary>
/// <param name="y"></param>
void dispPopYaku( Yaku y )
{
	this.pictYaku1.Visibility = Windows.UI.Xaml.Visibility.Visible;
	this.pictYaku2.Visibility = Windows.UI.Xaml.Visibility.Visible;
	this.pictYaku3.Visibility = Windows.UI.Xaml.Visibility.Visible;
	this.pictYaku4.Visibility = Windows.UI.Xaml.Visibility.Visible;
	this.pictYaku5.Visibility = Windows.UI.Xaml.Visibility.Visible;
	if (y.GoKou != null)
	{
		this.popYakuText.Text = "五光";
		this.pictYaku1.Source = CardUI.GetResName(y.GoKou[0].ID);
		this.pictYaku2.Source = CardUI.GetResName(y.GoKou[1].ID);
		this.pictYaku3.Source = CardUI.GetResName(y.GoKou[2].ID);
		this.pictYaku4.Source = CardUI.GetResName(y.GoKou[3].ID);
		this.pictYaku5.Source = CardUI.GetResName(y.GoKou[4].ID);
	}
// 略

	this.sbPopYaku.Completed += sbPopYaku_Completed;
	this.popYaku.IsOpen = true;
	this.sbPopYaku.Begin();
}

/// <summary>
/// タイマー完了時
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void sbPopYaku_Completed(object sender, object e)
{
	this.sbPopYaku.Stop();
	this.popYaku.IsOpen = false;
}

これで、適当なところで dispPopYaku メソッドを呼び出せばポップアップが表示されます。

アニメーションは非同期で行われるので、下記のように、dispPopYaku でポップアップを表示させた後は、_curPlayer.GetCard などのメソッドは即時実行されます。さきゆきは、場からマッチしたときのアニメーションも追加するので、このあたりの整合性(画面の動き的な整合性)をあわせる必要がありますね。

/// <summary>
/// 場に出した札をクリックしてマッチさせる
/// </summary>
/// <param name="obj"></param>
void baControl1_ClickPutCard(Card obj)
{
	var lst = _board.Game.MatchBa(_board.Ba, _board.Ba.PlayerCard, _curPlayer);
	if (lst != null)
	{
		// カードが決定した場合、画面を更新
		_board.Ba.GetCard(lst);
		// 役の計算
		Yaku y = _board.Game.CalcYaku(lst, _curPlayer.TakenCards);
		if (y != null)
		{
			// 一定時間、役を表示
			dispPopYaku(y);
		}
		// 手持ちに加える
		_curPlayer.GetCard(lst);
		// 画面の更新
		ScrUpdate();
	}
}

■ダイアログをタップした瞬時の閉じる処理を追加

自動的にポップアップは閉じるのですが、タップしたときに即時終了させる処理も追加しておきます。

ポップアップの grid 部分に Tapeed イベントを追加しておきます。ためしに Popup 自身に Tapped を追加してみたのですが呼び出されませんでした。

<Popup x:Name="popYaku" 
        Margin="320,160,-320,328" Grid.Row="1">
    <Grid Background="Red" Height="213" Width="399"
            Tapped="popClick"
            >
        <TextBlock 
            x:Name="popYakuText"
            FontSize="40"
            HorizontalAlignment="Left" Margin="34,32,0,0" TextWrapping="Wrap" Text="役ができました" VerticalAlignment="Top"/>
        <Image x:Name="pictYaku1" HorizontalAlignment="Left" Height="100" Margin="34,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>
        <Image x:Name="pictYaku2" HorizontalAlignment="Left" Height="100" Margin="103,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>
        <Image x:Name="pictYaku3" HorizontalAlignment="Left" Height="100" Margin="172,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>
        <Image x:Name="pictYaku4" HorizontalAlignment="Left" Height="100" Margin="241,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>
        <Image x:Name="pictYaku5" HorizontalAlignment="Left" Height="100" Margin="310,96,0,0" VerticalAlignment="Top" Width="64" Source="/Images/FC097-2.png"/>

    </Grid>
</Popup>

アニメーションの完了イベントを発生させるために、SkipToFill メソッドを使って最終点まで移動させます。これでタップしたときには即時終了します。

/// <summary>
/// ポップアップをタップした時
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void popClick(object sender, TappedRoutedEventArgs e)
{
	this.sbPopYaku.SkipToFill();
}

他のアニメーションとの整合性もあるのですが(札を手持ちに加えるアニメーションとか)、ひとまず役をできたときのポップアップはこれで ok ということで。

カテゴリー: C#, WinRT パーマリンク