モーダルダイアログ風なものができたので、これを応用して自動的に閉じるダイアログを作ります。
のようにメッセージを表示して、しばらくしたら閉じるっていうメッセージダイアログです。よくゲームであるパターンだし、他のアプリでも応用が利きます。
フォームアプリの場合にはタイマーを使ってイベント待ちをするのが定番ですが、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 ということで。



