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

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

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

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

■popup でダイアログを作る

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

<Popup x:Name=&quot;popYaku&quot; 
        Margin=&quot;320,160,-320,328&quot; Grid.Row=&quot;1&quot;>
    <Grid Background=&quot;Red&quot; Height=&quot;213&quot; Width=&quot;399&quot;>
        <TextBlock 
            x:Name=&quot;popYakuText&quot;
            FontSize=&quot;40&quot;
            HorizontalAlignment=&quot;Left&quot; Margin=&quot;34,32,0,0&quot; TextWrapping=&quot;Wrap&quot; Text=&quot;役ができました&quot; VerticalAlignment=&quot;Top&quot;/>
        <Image x:Name=&quot;pictYaku1&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;34,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>
        <Image x:Name=&quot;pictYaku2&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;103,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>
        <Image x:Name=&quot;pictYaku3&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;172,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>
        <Image x:Name=&quot;pictYaku4&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;241,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>
        <Image x:Name=&quot;pictYaku5&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;310,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>
    </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=&quot;AppName&quot;>花札 こいこい</x:String>
    <Storyboard x:Name=&quot;sbPopYaku&quot;>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty=&quot;(UIElement.Opacity)&quot; Storyboard.TargetName=&quot;popYaku&quot;>
        	<EasingDoubleKeyFrame KeyTime=&quot;0:0:2.5&quot; Value=&quot;1&quot;/>
        	<EasingDoubleKeyFrame KeyTime=&quot;0:0:3&quot; Value=&quot;0&quot;/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Page.Resources>

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

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

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

/// <summary>
/// 役を表示
/// </summary>
/// <param name=&quot;y&quot;></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 = &quot;五光&quot;;
		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=&quot;sender&quot;></param>
/// <param name=&quot;e&quot;></param>
void sbPopYaku_Completed(object sender, object e)
{
	this.sbPopYaku.Stop();
	this.popYaku.IsOpen = false;
}

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

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

/// <summary>
/// 場に出した札をクリックしてマッチさせる
/// </summary>
/// <param name=&quot;obj&quot;></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=&quot;popYaku&quot; 
        Margin=&quot;320,160,-320,328&quot; Grid.Row=&quot;1&quot;>
    <Grid Background=&quot;Red&quot; Height=&quot;213&quot; Width=&quot;399&quot;
            Tapped=&quot;popClick&quot;
            >
        <TextBlock 
            x:Name=&quot;popYakuText&quot;
            FontSize=&quot;40&quot;
            HorizontalAlignment=&quot;Left&quot; Margin=&quot;34,32,0,0&quot; TextWrapping=&quot;Wrap&quot; Text=&quot;役ができました&quot; VerticalAlignment=&quot;Top&quot;/>
        <Image x:Name=&quot;pictYaku1&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;34,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>
        <Image x:Name=&quot;pictYaku2&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;103,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>
        <Image x:Name=&quot;pictYaku3&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;172,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>
        <Image x:Name=&quot;pictYaku4&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;241,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>
        <Image x:Name=&quot;pictYaku5&quot; HorizontalAlignment=&quot;Left&quot; Height=&quot;100&quot; Margin=&quot;310,96,0,0&quot; VerticalAlignment=&quot;Top&quot; Width=&quot;64&quot; Source=&quot;/Images/FC097-2.png&quot;/>

    </Grid>
</Popup>

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

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

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

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