locked
How to implement a Split View Page into an existing Windows 8.1 project?

    Question

  •  I started development in Windows 8 and upgraded to windows 8.1. In our Windows 8 version of the project before we upgraded we implemented a number of new Split pages that took advantage of the default sample data source.cs file to databind our pages to. Since upgrading to Windows 8.1 its proving really difficult to implement a new split page because Windows 8.1 implements a split page differently. Its reads from a Json file that contains all your hard coded data, creates the dataclass in the data source file and binds to a collection of data groups and items in your load and save state navigation helper methods in the code behind file, of the split page

    I implemented a new folder "SplitDataModel" with two files - Factsdatasource.cs file and Sampledatasource.json file. (I had to copy this from a template project because I was unable to insert a new Json file in Visual studio?)

    FactsDataSource.cs :

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Threading.Tasks;
    using Windows.Data.Json;
    using Windows.Storage;
    using Windows.UI.Xaml.Media;
    using Windows.UI.Xaml.Media.Imaging;
    using Windows.UI.Xaml.Data;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Controls.Primitives;
    using Windows.UI.Xaml.Input;
    
    
    // The data model defined by this file serves as a representative example of a strongly-typed
    // model.  The property names chosen coincide with data bindings in the standard item templates.
    //
    // Applications may use this model as a starting point and build on it, or discard it entirely and
    // replace it with something appropriate to their needs. If using this model, you might improve app 
    // responsiveness by initiating the data loading task in the code behind for App.xaml when the app 
    // is first launched.
    
    namespace IME.FactsData
    {
        /// <summary>
        /// Generic item data model.
        /// </summary>
    
        public class FactsDataItem
        {
            public FactsDataItem(String uniqueId, String title, String subtitle, String imagePath, String description, String content)
            {
                this.UniqueId = uniqueId;
                this.Title = title;
                this.Subtitle = subtitle;
                this.Description = description;
                this.ImagePath = imagePath;
                this.Content = content;
            }
    
            public string UniqueId { get; private set; }
            public string Title { get; private set; }
            public string Subtitle { get; private set; }
            public string Description { get; private set; }
            public string ImagePath { get; private set; }
            public string Content { get; private set; }
    
            public override string ToString()
            {
                return this.Title;
            }
        }
    
        public class FactsDataGroup
        {
            public FactsDataGroup(String uniqueId, String title, String subtitle, String imagePath, String description)
            {
                this.UniqueId = uniqueId;
                this.Title = title;
                this.Subtitle = subtitle;
                this.Description = description;
                this.ImagePath = imagePath;
                this.Items = new ObservableCollection<FactsDataItem>();
            }
    
            public string UniqueId { get; private set; }
            public string Title { get; private set; }
            public string Subtitle { get; private set; }
            public string Description { get; private set; }
            public string ImagePath { get; private set; }
            public ObservableCollection<FactsDataItem> Items { get; private set; }
    
            public override string ToString()
            {
                return this.Title;
            }
        }
    
        /// <summary>
        /// Creates a collection of groups and items with content read from a static json file.
        /// 
        /// SampleDataSource initializes with data read from a static json file included in the 
        /// project.  This provides sample data at both design-time and run-time.
        /// </summary>
        public sealed class FactsDataSource
        {
            private static FactsDataSource _SampleDataSource = new FactsDataSource();
    
            private ObservableCollection<FactsDataGroup> _groups = new ObservableCollection<FactsDataGroup>();
            public ObservableCollection<FactsDataGroup> Groups
            {
                get { return this._groups; }
            }
    
            public static async Task<IEnumerable<FactsDataGroup>> GetGroupsAsync()
            {
                await _SampleDataSource.GetDataAsync();
    
                return _SampleDataSource.Groups;
            }
    
            public static async Task<FactsDataGroup> GetGroupAsync(string uniqueId)
            {
                await _SampleDataSource.GetDataAsync();
                // Simple linear search is acceptable for small data sets
                var matches = _SampleDataSource.Groups.Where((group) => group.UniqueId.Equals(uniqueId));
                if (matches.Count() == 1) return matches.First();
                return null;
            }
    
            public static async Task<FactsDataItem> GetItemAsync(string uniqueId)
            {
                await _SampleDataSource.GetDataAsync();
                // Simple linear search is acceptable for small data sets
                var matches = _SampleDataSource.Groups.SelectMany(group => group.Items).Where((item) => item.UniqueId.Equals(uniqueId));
                if (matches.Count() == 1) return matches.First();
                return null;
            }
           
            private async Task GetDataAsync()
            {
                if (this._groups.Count != 0)
                    return;
    
                Uri dataUri = new Uri("ms-appx:///SplitDataModel/SampleData.json");
    
                StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(dataUri);
                string jsonText = await FileIO.ReadTextAsync(file);
                JsonObject jsonObject = JsonObject.Parse(jsonText);
                JsonArray jsonArray = jsonObject["Groups"].GetArray();
    
                foreach (JsonValue groupValue in jsonArray)
                {
                    JsonObject groupObject = groupValue.GetObject();
                    FactsDataGroup group = new FactsDataGroup(groupObject["UniqueId"].GetString(),
                                                                groupObject["Title"].GetString(),
                                                                groupObject["Subtitle"].GetString(),
                                                                groupObject["ImagePath"].GetString(),
                                                                groupObject["Description"].GetString());
    
                    foreach (JsonValue itemValue in groupObject["Items"].GetArray())
                    {
                        JsonObject itemObject = itemValue.GetObject();
                        group.Items.Add(new FactsDataItem(itemObject["UniqueId"].GetString(),
                                                           itemObject["Title"].GetString(),
                                                           itemObject["Subtitle"].GetString(),
                                                           itemObject["ImagePath"].GetString(),
                                                           itemObject["Description"].GetString(),
                                                           itemObject["Content"].GetString()));
                    }
                    this.Groups.Add(group);
                }
            }
        }
    
    }

    The MyFacts.xaml  - The split page

    <Page
        x:Name="pageRoot"
        x:Class="IME.Advice.Facts.MyFacts"
        DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:IME.Advice.Facts"
        xmlns:common="using:IME.Common"
        xmlns:data="using:IME.FactsData"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Page.Resources>
            <!-- Collection of items displayed by this page -->
            <CollectionViewSource
            x:Name="itemsViewSource"
            Source="{Binding Items}" />
          <!-- d:Source="{Binding Groups[0].Items, Source={d:DesignData Source=/SplitDataModel/SampleData.json, Type=data:SampleDataSource}}"/> 
            -->
        </Page.Resources>
    
    
        <!-- Top App Bar-->
        <Page.TopAppBar>
            <AppBar>
                <!-- AppBar content -->
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="901*"/>
                        <ColumnDefinition Width="465*"/>
    
                    </Grid.ColumnDefinitions>
    
                    <StackPanel x:Name="LeftPanel" Orientation="Horizontal" Grid.Column="0" Background="#F0000000">
                        <Button x:Name="Home" Style="{StaticResource HomeAppBarButtonStyle}" Click="Home_Click"/>
                    </StackPanel>
    
                    <StackPanel x:Name="RightPanel" Orientation="Horizontal" Grid.Column="1">
                        <Button x:Name="My_Facts" Width="133" Height="85" Content="My Situations" Margin="0,11,0,10" BorderBrush="White" Click="MySituations_Click" />
    
                    </StackPanel>
                </Grid>
            </AppBar>
        </Page.TopAppBar>
    
    
    
        <!--
            This grid acts as a root panel for the page that defines two rows:
            * Row 0 contains the back button and page title
            * Row 1 contains the rest of the page layout
        -->
        <Grid Background="White"
              DataContext="{Binding Group}">
          <!--  d:DataContext="{Binding Source={d:DesignData Source=/SplitDataModel/SampleData.json, Type=data:FactsDataSource
            }}"/> -->
        
        <Grid.ChildrenTransitions>
                <TransitionCollection>
                    <EntranceThemeTransition/>
                </TransitionCollection>
            </Grid.ChildrenTransitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="140"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition x:Name="primaryColumn" Width="420"/>
                <ColumnDefinition x:Name="secondaryColumn" Width="*"/>
            </Grid.ColumnDefinitions>
            
    
            <!-- Back button and page title -->
            <Grid x:Name="titlePanel" Grid.ColumnSpan="2">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.Background>
                    <SolidColorBrush
                Color="#FF60A917" />
                </Grid.Background>
                <Button x:Name="backButton" Margin="39,59,39,0" Command="{Binding NavigationHelper.GoBackCommand, ElementName=pageRoot}"
                            Style="{StaticResource NavigationBackButtonNormalStyle}"
                            VerticalAlignment="Top"
                            AutomationProperties.Name="Back"
                            AutomationProperties.AutomationId="BackButton"
                            AutomationProperties.ItemType="Navigation Button"/>
                <TextBlock x:Name="pageTitle" Text="My Facts" Style="{StaticResource HeaderTextBlockStyle}" Grid.Column="1" 
                           TextWrapping="NoWrap" VerticalAlignment="Bottom" Margin="0,0,0,40"/>
               
            </Grid>
    
            <!-- Vertical scrolling item list -->
            <ListView
                x:Name="itemListView"
                AutomationProperties.AutomationId="ItemsListView"
                AutomationProperties.Name="Items"
                TabIndex="1"
                Grid.Row="1"
                Margin="-10,-10,0,0"
                Padding="120,0,0,60"
                ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
                IsSwipeEnabled="False"
                SelectionChanged="ItemListView_SelectionChanged">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <Grid Margin="6">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="60" Height="60">
                                <Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
                            </Border>
                            <StackPanel Grid.Column="1" Margin="10,0,0,0">
                                <TextBlock Text="{Binding Title}" Style="{StaticResource TitleTextBlockStyle}" TextWrapping="NoWrap" MaxHeight="40"/>
                                <TextBlock Text="{Binding Subtitle}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/>
                            </StackPanel>
                        </Grid>
                    </DataTemplate>
                </ListView.ItemTemplate>
                <ListView.ItemContainerStyle>
                    <Style TargetType="FrameworkElement">
                        <Setter Property="Margin" Value="0,0,0,10"/>
                    </Style>
                </ListView.ItemContainerStyle>
            </ListView>
    
    
            <!-- Details for selected item add this below data context d:DataContext="{Binding Groups[0].Items[0], Source={d:DesignData Source=/SplitDataModel/SampleData.json, Type=data:SampleDataSource}}" 
                -->
            <ScrollViewer
                x:Name="itemDetail"
                AutomationProperties.AutomationId="ItemDetailScrollViewer"
                Grid.Column="1"
                Grid.RowSpan="2"
                Padding="60,0,66,0"
                DataContext="{Binding SelectedItem, ElementName=itemListView}"
               
                HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"
                ScrollViewer.HorizontalScrollMode="Disabled" ScrollViewer.VerticalScrollMode="Enabled"
                ScrollViewer.ZoomMode="Disabled">
    
                <Grid x:Name="itemDetailGrid" Margin="0,60,0,50">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
    
                    <Image Grid.Row="1" Margin="0,0,20,0" Width="180" Height="180" Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/>
                    <StackPanel x:Name="itemDetailTitlePanel" Grid.Row="1" Grid.Column="1">
                        <TextBlock x:Name="itemTitle" Margin="0,-10,0,0" Text="{Binding Title}" Style="{StaticResource SubheaderTextBlockStyle}"/>
                        <TextBlock x:Name="itemSubtitle" Margin="0,0,0,20" Text="{Binding Subtitle}" Style="{StaticResource SubtitleTextBlockStyle}"/>
                    </StackPanel>
                    <TextBlock Grid.Row="2" Grid.ColumnSpan="2" Margin="0,20,0,0" Text="{Binding Content}" Style="{StaticResource BodyTextBlockStyle}"/>
                </Grid>
            </ScrollViewer>
    
            <VisualStateManager.VisualStateGroups>
    
                <!-- Visual states reflect the application's view state -->
                <VisualStateGroup x:Name="ViewStates">
                    <VisualState x:Name="PrimaryView" />
                    <VisualState x:Name="SinglePane">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="primaryColumn" Storyboard.TargetProperty="Width">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="*"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="secondaryColumn" Storyboard.TargetProperty="Width">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetail" Storyboard.TargetProperty="Visibility">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Padding">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="120,0,90,60"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                    <!--
                        When an item is selected and only one pane is shown the details display requires more extensive changes:
                         * Hide the master list and the column it was in
                         * Move item details down a row to make room for the title
                         * Move the title directly above the details
                         * Adjust padding for details
                     -->
                    <VisualState x:Name="SinglePane_Detail">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="primaryColumn" Storyboard.TargetProperty="Width">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemListView" Storyboard.TargetProperty="Visibility">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetail" Storyboard.TargetProperty="(Grid.Row)">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetail" Storyboard.TargetProperty="(Grid.RowSpan)">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="titlePanel" Storyboard.TargetProperty="(Grid.Column)">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetailGrid" Storyboard.TargetProperty="Margin">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="0,0,0,60"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemDetail" Storyboard.TargetProperty="Padding">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="120,0,90,0"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Grid>
    </Page>


    When attempting to bind the grid and list view in MyFacts.xaml to the datasource file with the following lines in the split page:

    d:Source="{Binding Groups[0].Items, Source={d:DesignData Source=/SplitDataModel/SampleData.json,

    Type=data:FactsDataSource}}"/

    Xaml tells me it cannot find the type "data:FactsDataSource" but when I change it to "SampleDataSource" it recognises that file, which was previously implemented for the Windows 8 version split page? I can't work out why it's only recognising that file.

    - Am I missing something in my databinding statement above? 

    -Does anyone have experience in implementing a new splitpage in Windows 8.1 and could help me out please?

    Thanks
    --Bronagh


    Sunday, April 13, 2014 1:02 PM

All replies

  • Hi Bronagh,

    Could you share a repro with us for a better analysis?

    If my understanding is correct, you create a Class named FactsDataSource under namespace IME.FactsData, and the code is almost like what the app Split template project does? You can create a new Split project to see what's the difference.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Monday, April 14, 2014 8:26 AM
    Moderator