Lazy load FlipView content

205 Views Asked by At

I have a FlipView with 2 tabs in UWP which I think behaves the as TabControl in WPF. I am following the post provided here lazy load tab control contents by Ruben Bartelink. But my problem is when I go to the screen, I see the breakpoint hitting all the InitilizeComponent() for all the user controls. Please help.

Here is my xaml:

<FlipView 
    x:Name="FlipViewStatus" Grid.Row="2"
    Style="{StaticResource FlipViewStyleNoPageButtons}"
    Background="Transparent"
    SelectedIndex="{x:Bind ViewModel.SelectedTabIndex, Mode=TwoWay}">
    <FlipView.ItemContainerStyle>
        <Style TargetType="FlipViewItem">
            <Setter Property="Padding" Value="2 4 4 2"/>
        </Style>
    </FlipView.ItemContainerStyle>
    <FlipViewItem 
        x:Name="FlipViewItemOngoing" 
        Content="{x:Bind ViewModel.VmOnGoingRuns,Mode=OneWay}">
        <FlipViewItem.ContentTemplate>
            <DataTemplate x:DataType="model:VmOnGoingRunsCollection">
                <Grid x:Name="FlipViewItemOngoingGrid" 
                      PointerWheelChanged="PointerWheelIgnore">
                    <local:StatusRunsView 
                        x:Name="StatusOngoingRuns"
                        RecentSpecimenRuns="{x:Bind OnGoingRunsCollection, 
                                                    Mode=OneWay}"
                        IsLoadingRuns="{x:Bind IsLoadingOngoingRuns, 
                                               Mode=OneWay}"/>
                </Grid>
            </DataTemplate>
        </FlipViewItem.ContentTemplate>
    </FlipViewItem>
    
    <FlipViewItem 
        x:Name="FlipViewItemSampleOutput" 
        Content="{x:Bind ViewModel.OutputStatusViewModel,Mode=OneWay}">
        <FlipViewItem.ContentTemplate>
            <DataTemplate>
                <Grid x:Name="FlipViewItemSampleOutputGrid" 
                      PointerWheelChanged="PointerWheelIgnore">
                    <local:StatusSampleOutputView x:Name="StatusSampleOutput" 
                                                  ViewModel="{Binding}"/>
                </Grid>
            </DataTemplate>
        </FlipViewItem.ContentTemplate>
    </FlipViewItem>
</FlipView>

In the ViewModel associated to this FlipView I have some code as follows.

public class ViewModel : BindableBaseThreadSafe
{
    private ISampleOutputStatusViewModel _outputStatusViewModel;
    public ISampleOutputStatusViewModel OutputStatusViewModel
    {
        get => _outputStatusViewModel;
        set => Set(ref _outputStatusViewModel, value);
    }

    public int SelectedTabIndex
    {
        //I am debugging here and the tab index is correct
        get => _selectedTabIndex; 
        set
        {
            if (Set(ref _selectedTabIndex, value))
            {
                LoadData((StatusList)_selectedTabIndex)
                    .Await(OnErrorLoadingData);
            }
        }
    }

    public ViewModel()
    {
        VmOnGoingRuns = 
            lifetimeScope.Resolve<VmOnGoingRunsCollection>();

        VmOnGoingRuns.OnGoingRunsCollection = 
            new ObservableCollection<VmStatusSpecimen>();
    }

    //The listname enum is being set from xaml.
    private async Task LoadData(StatusList listName)
    {
        switch (listName)
        {
            case StatusList.OngoingRuns:
                await LoadOngoingRuns();
                break;

            // This code executes correctly when the user selects the 
            // Output tab in the FlipView. 
            case StatusList.Output:
                {
                    OutputStatusViewModel = _lifetimeScope
                        .Resolve<ISampleOutputStatusViewModel>();

                    break;
                }
        }
    }
}

My problem is as soon as I navigate to this FlipView page, I see the breakpoint hitting the StatusSampleOutputView.xaml.cs InitilizeComponent(). I want it to lazy load, in other words only when the user selects the StatusSampleOutputView, I want this view to load. Please help what am I doing wrong.,

3

There are 3 best solutions below

0
On

ContentControl can have lazy loading, you can try following:

  1. Wrap actual item view model into some lightweight dummy view model with single property
  2. In the FlipView item template place ContentControl and bind it to that property
  3. Create EmptyWhenNullTemplateSelector for ContentControl, return new DataTemplate() for null and actual data template when data is present
  4. When selection of the FlipView changes, load data and set actual view model
3
On

FlipView control from uwp is different from the TabControl in wpf, you can’t expect it to implement your requirement like you use TabControl in wpf app. Besides, FlipView derives from ItemsControl, which has a lazy load called UI virtualization. This means that UI elements represtenting the items are created on demand.

For an items control bound to multiple items collection, when items are close to being scrolled into view (a few pages away), the framework can generate UI for these items and caches them. Therefore, you could try to create multiple items(such as 100 items), then check if the framework generates UI for all items at the same time.

0
On

Uwp has a property called x:Load on a UI element. In my specific case if I wanted to lazy load a tab, I have a bool property in the ViewModel that Implements INotifyPropertyChanged, I would switch between true or false. On the other hand if you want to set the x:Load property of a UIElement in the xaml.cs, you need to do something like this.

if (sender is FrameworkElement frameworkElement)
        {
            // This loads the child UI elements when the expander is expanded
            frameworkElement.FindName("ListViewPanels");
        }