しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure Icon Quiz アプリを Windows Phone 8.1 向けに作った

昔 HTML5 で作った Azure のアイコンからサービスを当てるクイズを、Windows Phone 8.1 で再実装してストアで公開してみました。日本語はめんどくさかったので入れてません。

起動するとこんな画面が表示されます。HDInsight はちょっとアイコンが古いです。

f:id:shiba-yan:20141002171803p:plain

タイトルに表示されているサービスのアイコンを選んで、次に進んでいくだけの簡単な仕様です。

最後まで回答すると答え合わせ画面になるので、何を間違ったか確認出来ます。

f:id:shiba-yan:20141002172005p:plain

個人的には BizTalk Service と Traffic Manager が覚えにくいです。

開発でめんどくさかったこと

最初は ListBox の ItemsPanel として WrapGrid を使おうとすると、何故か実行時エラーになってしまったので ListView で実装しました。すると、今度は項目を選択した時のスタイルが正しく適用されない問題にぶち当たったので、スタイルでテンプレートを弄って対応しました。

<Style x:Key="ListViewItemStyle1" TargetType="ListViewItem">
    <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
    <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="TabNavigation" Value="Local"/>
    <Setter Property="IsHoldingEnabled" Value="False"/>
    <Setter Property="Margin" Value="{ThemeResource ListViewItemMargin}"/>
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
    <Setter Property="VerticalContentAlignment" Value="Top"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListViewItem">
                <Border x:Name="OuterContainer" RenderTransformOrigin="0.5,0.5">
                    <Border.RenderTransform>
                        <ScaleTransform x:Name="ContentScaleTransform"/>
                    </Border.RenderTransform>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualStateGroup.Transitions>
                                <VisualTransition From="Pressed" To="Normal">
                                    <Storyboard>
                                        <PointerUpThemeAnimation Storyboard.TargetName="TiltContainer"/>
                                    </Storyboard>
                                </VisualTransition>
                            </VisualStateGroup.Transitions>
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <PointerDownThemeAnimation Storyboard.TargetName="TiltContainer"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="CheckboxPressed">
                                <Storyboard>
                                    <PointerDownThemeAnimation Storyboard.TargetName="CheckboxTiltContainer"/>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="NormalRectangle">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource CheckBoxPressedBackgroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="CheckGlyph">
                                        <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource CheckBoxPressedForegroundThemeBrush}"/>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected"/>
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SelectedBorder"/>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SelectedCheckMark"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="SelectedUnfocused">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SelectedBorder"/>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="SelectedCheckMark"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Grid x:Name="ReorderHintContent" Background="Transparent">
                        <Border x:Name="ContentContainer">
                            <Border x:Name="TiltContainer">
                                <Border x:Name="ContentBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                                    <Border.RenderTransform>
                                        <TranslateTransform x:Name="ContentBorderTranslateTransform"/>
                                    </Border.RenderTransform>
                                    <Grid>
                                        <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                        <TextBlock x:Name="PlaceholderTextBlock" AutomationProperties.AccessibilityView="Raw" Foreground="{x:Null}" IsHitTestVisible="False" Margin="{TemplateBinding Padding}" Opacity="0" Text="Xg"/>
                                        <Rectangle x:Name="PlaceholderRect" Fill="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" IsHitTestVisible="False" Visibility="Collapsed"/>
                                    </Grid>
                                </Border>
                            </Border>
                        </Border>
                        <Border x:Name="SelectedBorder" BorderBrush="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}" BorderThickness="{ThemeResource GridViewItemMultiselectBorderThickness}" IsHitTestVisible="False" Opacity="0">
                            <Grid x:Name="SelectedCheckMark" HorizontalAlignment="Right" Height="34" Opacity="0" VerticalAlignment="Top" Width="34">
                                <Path x:Name="SelectedEarmark" Data="M0,0 L40,0 L40,40 z" Fill="{ThemeResource ListViewItemSelectedBackgroundThemeBrush}" Stretch="Fill"/>
                                <Path x:Name="SelectedGlyph" Data="M0,123 L39,93 L124,164 L256,18 L295,49 L124,240 z" Fill="{ThemeResource ListViewItemCheckThemeBrush}" FlowDirection="LeftToRight" HorizontalAlignment="Right" Height="14.5" Margin="0,1,1,0" Stretch="Fill" VerticalAlignment="Top" Width="17"/>
                            </Grid>
                        </Border>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

と言っても、変更点は VSM の選択状態時に SelectedBorder の Opacity を変更するようにしただけです。何故 0 のままになっているのか理由は分かりませんでしたが、とりあえずこれで動いたので良いとします。

そして ListBox を答え合わせ画面に使ったところ、選択不可という設定が無かったので選択状態のスタイルを削除することで対応しました。

<Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="TabNavigation" Value="Local"/>
    <Setter Property="Padding" Value="6.5,8"/>
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Border x:Name="LayoutRoot" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                    <Grid x:Name="InnerGrid" Background="Transparent">
                        <ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ItemsControl を最初に使ってみましたが、何故かスクロール出来なくなったので諦めました。WPF の時と比べて思ったより違っているので戸惑います。