0

I have a TabControl with several tabs. The first and main one is very simple one and takes virtually no time at all to load. The second one on the other hand is a representation of hundreds of complex objects, and takes about 1-3 seconds. The application fires up rapidly, but as soon as you click on the second tab, the application freezes for a short while, loading the Tab Control.

This is a quick illustration of the XAML code:

<Window x:Class="MyProgramme.MyMainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
         <TabControl VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0">
            <TabItem Header="Simple View" >
                <!-- Main view. Loads instantly. -->
                <ContentPresenter x:Name="m_simple"/>                    
            </TabItem>
            <TabItem Header="Heavy View" > 
                <!-- Takes about 1-3 seconds to load-->
                <ContentPresenter x:Name="m_heavy"/>
            </TabItem>
         </TabControl>
    </Grid>
</Window>

Obviously, this waiting is not very user friendly, and I would like a way to explicitly load the second tab whenever it's convenient, which will be either at start-up, or whenever the UI thread is not too busy and can take the load. Is there a way of loading this tab without stalling the user's work flow?

Yellow
  • 3,955
  • 6
  • 45
  • 74

1 Answers1

1

If you are loading the data for the tab in the constructor, that would be the reason for the freeze.

Rather use the Window's Loaded event instead and if possible, try kick off the heavy load in a background thread. Loaded is triggered once the UI is drawn leading to a better user experience as the UI itself does not appear to freeze.

You should also consider a BusyIndicator or ProgressBar for the second tab while the background load is running to indicate to the user that a long running process is happening.

toadflakz
  • 7,764
  • 1
  • 27
  • 40
  • Thanks for your suggestion. Could you perhaps be a bit ore specific about how to 'kick off the heavy load'? I can attach something to the `Loaded` trigger, but I'm not sure how to explicitly load the heavy load tab. – Yellow Feb 17 '15 at 13:18
  • 2
    Use a `BackgroundWorker` or `TPL Task` to do your processing and when the data is ready to be loaded into the controls on the tab itself, wrap the calls in a Dispatcher.Invoke() to modify the `ViewModel` properties you have bound the UI too (including hiding the `BusyIndicator`). – toadflakz Feb 17 '15 at 13:21
  • A warning about this - WPF unloads tabs which are not in use, so switching away from the tab and back again would trigger the `Loaded` event another time. A common workaround is to extend the `TabControl` to change this behavior so it stores the `ContentPresenter` of each tab item, and simply restores it whenever the tab is activated again. This prevents the constant loading and unloading of tab items when the user switches tabs. You can find an example of the extended tab control [here](http://stackoverflow.com/a/3627308/302677) – Rachel Feb 17 '15 at 17:35
  • @Rachel: Good point about `TabItem` `Loaded` event. I should clarify that I meant the `Window` `Loaded` event rather than the individual `TabItem` as the OP suggests that the initial load of the `Window` is the apparent UI freeze hotspot. PS. Love your blogpost on moving from `WinForms` to `WPF`! ;) – toadflakz Feb 18 '15 at 09:49