While trying to reduce the loading time for our SurfCube 3D Browser app, I realized that loading a 100 or so history items to a ViewModel property directly bound to the UI may not be the best idea. It takes up a long time (like 0.5 seconds) to render the items in the list, and the user may never see the history during his / her session. The solution is obviously to load the items only when needed.
In the upcoming version of SurfCube, we will have a Pivot for choosing between Favorites and History. This is what the top side of the Cube looks like:
For most browsing sessions, the user won’t even visit the history at all. I only want to spend precious CPU cycles on rendering the history when needed. So, I need a way for my ViewModel to know when to actually load the history items to the ObservableCollection bound to the list on the History PivotItem.
Unfortunately, the PivotItem control does not expose any event that fires when it is activated. Technically, we could use the Pivot’s SelectionChanged event here. But the arguments of the event are PivotItems – and knowing about UI controls is a big no-no for VIewModels.
Well, Triggers to the rescue! By creating a simple trigger, and adding it to the PivotItem, we should be able to notify the ViewModel that it’s time to fill the ObservableCollection with data. Here is the code for the Trigger:
1: public class PivotItemActivatedTrigger : TriggerBase<PivotItem>
3: protected override void OnAttached()
5: AssociatedObject.Loaded += (o, eventArgs) =>
7: var parentPivot = AssociatedObject.Parent as Pivot;
9: if (parentPivot == null)
10: throw new InvalidOperationException("Parent of a PivotItem should be a Pivot");
12: parentPivot.SelectionChanged += (sender, args) =>
14: if (parentPivot.SelectedItem == AssociatedObject)
The Action we are invoking can be anything. Since I want to notify the ViewModel, I am using the CallDatacontextMethodAction as described in my older article “A Designer-friendly Approach to MVVM”.
After the Trigger is added to the project, this is how I am using it in Blend:
First, I drop the CallDatacontextMethodAction on the historyPivotItem.
Then click the New button for the TriggerType:
Select PivotItemActivatedTrigger in the dialog, then click OK:
Finally, enter the method name:
One word of advice though: the trigger actually fires in the middle of the Pivot’s animation. If what you are doing in the EnsureHistory method is longer than a dozen or so milliseconds, make sure you fire up a background thread to do it.
Please let me know if you found this tip useful!
Jan 23 2011, 03:49 AM