かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

Universal Windows appで同じページで電話とパソコンの見た目を切り替える方法

といったらVSMしかないでしょう。強引に#if~#endifで。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace App31
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private MainPageViewModel viewModel = new MainPageViewModel();
        public MainPage()
        {
            this.InitializeComponent();
            this.DataContext = this.viewModel;

            // VSMの切り替え
            Window.Current.CoreWindow.SizeChanged += (_, __) => this.ViewStateChange();
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            // VSMの切り替え
            this.ViewStateChange();

            // ダミーデータ突っ込み
            foreach (var num in Enumerable.Range(0, 100))
            {
                this.viewModel.Numbers.Add(num);
            }
        }

        private void ViewStateChange()
        {
            // 電話とパソコンでVSM切り替え
#if WINDOWS_APP
            VisualStateManager.GoToState(this, "WindowsState", true);
#else
            VisualStateManager.GoToState(this, "PhoneState", true);
#endif
        }
    }
}

あとは、Styleなりなんなりを切り替えるページを作りこむ。

<Page
    x:Class="App31.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App31"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DataContext="{d:DesignInstance local:MainPageViewModel, IsDesignTimeCreatable=True}" Loaded="Page_Loaded">
    <Page.Resources>
        <DataTemplate x:Key="NumberDataTemplate">
            <Grid>
                <Border BorderThickness="1" Width="250" Height="250" Background="#FF06007A">
                    <TextBlock TextWrapping="Wrap" Text="{Binding Mode=OneWay}" Style="{StaticResource HeaderTextBlockStyle}" VerticalAlignment="Center" HorizontalAlignment="Center" FontFamily="Brush Script MT"/>
                </Border>
            </Grid>
        </DataTemplate>
        <Style x:Key="WindowStyle" TargetType="GridView">
            <Setter Property="ItemTemplate" Value="{StaticResource NumberDataTemplate}"/>
            <Setter Property="Padding" Value="120, 10, 0, 8" />
         </Style>
        <DataTemplate x:Key="PhoneNumberDataTemplate">
            <Grid Margin="5">
                <Border BorderThickness="1" Width="75" Height="75" Background="#FF000F53">
                    <TextBlock TextWrapping="Wrap" Text="{Binding Mode=OneWay}" Style="{StaticResource HeaderTextBlockStyle}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                </Border>
            </Grid>
        </DataTemplate>
        <Style x:Key="PhoneStyle" TargetType="GridView">
            <Setter Property="ItemTemplate" Value="{StaticResource PhoneNumberDataTemplate}"/>
            <Setter Property="Padding" Value="10, 10" />
        </Style>
    </Page.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="VisualStateGroup">
                <VisualState x:Name="WindowsState"/>
                <VisualState x:Name="PhoneState">
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="appBarButton">
                            <DiscreteObjectKeyFrame KeyTime="0">
                                <DiscreteObjectKeyFrame.Value>
                                    <Visibility>Collapsed</Visibility>
                                </DiscreteObjectKeyFrame.Value>
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Control.Style)" Storyboard.TargetName="gridView">
                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneStyle}">
                            </DiscreteObjectKeyFrame>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <AppBarButton x:Name="appBarButton" HorizontalAlignment="Stretch" Icon="Back" VerticalAlignment="Bottom" IsCompact="True" Margin="20,20,0,0"/>
            <TextBlock TextWrapping="Wrap" Text="GridView sample application" Style="{StaticResource HeaderTextBlockStyle}" Margin="20,30,0,0" FontFamily="Global User Interface"/>
        </StackPanel>
        <GridView x:Name="gridView" Grid.Row="1" ItemsSource="{Binding Numbers}" Margin="0,10,0,0" Style="{StaticResource WindowStyle}"/>

    </Grid>
</Page>

実行するとこんな感じのページになる。作りこめばいけなくないですね。

f:id:okazuki:20140413235142j:plain

f:id:okazuki:20140413235225j:plain

ただし

別々に作ったほうがページのコードの見通しがいいこともあるし、そもそも電話では使えないコントロールとかもあったりするので、ページまで同じコードにするかどうかはよくよく検討しよう。