Sun
Sun

Reputation: 4708

Virtualize the loading of Windows 8 XAML controls within a grid

I have a Window 8 RT store application (XAML/C#).

I have a form with a grid as the main component. That grid has 50 rows and each row has a TextBox. The grid is wrapped in a scrollviewer:

<ScrollViewer>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            ...50 rows
         </Grid.RowDefinitions>

         <TextBox Grid.Row="0" />
         <TextBox Grid.Row="1" />
         <TextBox Grid.Row="2" />
         ...
         <TextBox Grid.Row="50" />
    </Grid>
 </ScrollViewer>

When this form is loaded there is a notable pause while the page is loaded, I guessing this is because the page is being drawn.

What is the best way to speed this load process up? Can I virtualize the loading of the grid/Textboxes?

The slowness is notable once the application is running on a Windows Surface tablet, it's not bad on my design PC but that is obviously much more powerful.

Thanks in advance.

Upvotes: 0

Views: 377

Answers (1)

Filip Skakun
Filip Skakun

Reputation: 31724

You can use a ListView instead of the Grid in a ScrollViewer since that supports virtualization by default. Other than that - it might be nice to have some nicer user experience than a scary long list of TextBoxes to fill - maybe break up your form in multiple pages or use a FlipView to flip between groups of fields.

*EDIT - example

XAML

<Page
    x:Class="App10.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App10"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.Resources>
        <DataTemplate
            x:Key="TextFieldTemplate">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition
                        Height="Auto" />
                    <RowDefinition
                        Height="Auto" />
                </Grid.RowDefinitions>
                <TextBlock
                    Text="{Binding Label}" />
                <TextBox
                    Text="{Binding Value, Mode=TwoWay}"
                    Grid.Row="1" />
            </Grid>
        </DataTemplate>
        <DataTemplate
            x:Key="BoolFieldTemplate">
            <CheckBox
                Content="{Binding Label}"
                IsChecked="{Binding Value, Mode=TwoWay}" />
        </DataTemplate>
        <local:FieldTemplateSelector
            x:Key="FieldTemplateSelector"
            TextTemplate="{StaticResource TextFieldTemplate}"
            BoolTemplate="{StaticResource BoolFieldTemplate}" />
    </Page.Resources>
    <Grid
        Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <ListView
            x:Name="lv"
            ItemTemplateSelector="{StaticResource FieldTemplateSelector}" />
    </Grid>
</Page>

C#

using System.Collections.Generic;
using App10.Common;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace App10
{

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.lv.ItemsSource =
                new List<object>(
                    new object[]
                        {
                            new BoolFieldViewModel { Label = "Some bool field" },
                            new TextFieldViewModel { Label = "Some text field" },
                            new TextFieldViewModel { Label = "Some text field" },
                            new BoolFieldViewModel { Label = "Some bool field" },
                            new BoolFieldViewModel { Label = "Some bool field" },
                            new TextFieldViewModel { Label = "Some text field" },
                        });
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }
    }

    public abstract class FieldViewModel<T> : BindableBase
    {
        public string Label { get; set; }

        #region Value
        private T _value;
        public T Value
        {
            get { return _value; }
            set { this.SetProperty(ref _value, value); }
        }
        #endregion
    }

    public class BoolFieldViewModel : FieldViewModel<bool> { }
    public class TextFieldViewModel : FieldViewModel<string> { }

    public class FieldTemplateSelector : DataTemplateSelector
    {
        public DataTemplate BoolTemplate { get; set; }
        public DataTemplate TextTemplate { get; set; }

        protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
        {
            if (item is BoolFieldViewModel) return BoolTemplate;
            if (item is TextFieldViewModel) return TextTemplate;

            return base.SelectTemplateCore(item, container);
        }
    }
}

Upvotes: 1

Related Questions