Any time I am told “copy & paste [anything]” in more than one place, I start looking for alternatives. So it was when I was following this guide to adding page transitions to DataHub.
20 lines of XAML for each of 40 XAML files. Luckily I identified this early on and came up with a clean solution: Each of my PhoneApplicationPages would inherit from a single class, which I called BasePage.
namespace DataHub
{
public class BasePage : PhoneApplicationPage
{
public BasePage()
{
NavigationInTransition navInTransition = new NavigationInTransition();
navInTransition.Backward = new SlideTransition { Mode = SlideTransitionMode.SlideDownFadeIn };
navInTransition.Forward = new SlideTransition { Mode = SlideTransitionMode.SlideUpFadeIn };
NavigationOutTransition navOutTransition = new NavigationOutTransition();
navOutTransition.Backward = new SlideTransition { Mode = SlideTransitionMode.SlideDownFadeOut };
navOutTransition.Forward = new SlideTransition { Mode = SlideTransitionMode.SlideUpFadeOut };
TransitionService.SetNavigationInTransition(this, navInTransition);
TransitionService.SetNavigationOutTransition(this, navOutTransition);
this.SetValue(TiltEffect.IsTiltEnabledProperty, true);
}
along with these changes to the start & end XAML tags for each page:
<dh:BasePage xmlns:dh="clr-namespace:DataHub"> ... </dh:BasePage>
Much cleaner! With this bit of infrastructure worked out, I could move on to the real heart of the app.
Little did I know how useful this BasePage would be further down the line. So much so, I think I’ll have one in all future projects even if it’s initally blank.
A new problem arose when I was impementing better-together-dynamicorientationchanges-and-transitionframe. I noticed that if my device was held landscape and then the page was navigated, both the transition and the orientation change animations were playing. This was a pretty jarring user experience, and obviously in this case I wanted the transition animation only.
I had a twitter conversation with @DavidAns who replied “Avoiding it’d require specific (tricky?) changes”.
Luckily, I already had BasePage in place, so the changes were not so tricky:
protected static HybridOrientationChangesFrame MyHybridOrientationChangesFrame
{
get { return (HybridOrientationChangesFrame)(((App)(App.Current)).RootFrame); }
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
MyHybridOrientationChangesFrame.IsAnimationEnabled = false;
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
UIHelper.SetTimeout(300, () =>
{
MyHybridOrientationChangesFrame.IsAnimationEnabled = true;
});
}
}
Another use for BasePage appeared when Aaron, our UX designer, decided to include a “home” button on every DataHub page. Not wanting to include a circular reference (*ahem* AMAZON *ahem*) and specifically WANTING the page transitions between the starting point and home, I let BasePage do some automatic “back” navigation when a MainViewModel property was set.
void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (!IsCurrentPage) return;
if (!IsMainPage)
{
if (e.PropertyName == "GoHome")
{
if (App.ViewModel.GoHome)
{
UIHelper.SetTimeout(100, () =>
{
this.NavigationService.GoBack();
});
}
}
}
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
MyHybridOrientationChangesFrame.IsAnimationEnabled = false;
IsCurrentPage = false;
App.ViewModel.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(ViewModel_PropertyChanged);
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
App.ViewModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(ViewModel_PropertyChanged);
IsCurrentPage = true;
if (App.ViewModel.GoHome)
{
if (IsMainPage)
{
App.ViewModel.GoHome = false;
UIHelper.SetTimeout(300, () =>
{
MyHybridOrientationChangesFrame.IsAnimationEnabled = true;
});
}
else
{
UIHelper.SetTimeout(300, () =>
{
this.NavigationService.GoBack();
});
}
}
else
{
UIHelper.SetTimeout(300, () =>
{
MyHybridOrientationChangesFrame.IsAnimationEnabled = true;
});
}
}
This did require some careful coding any time a page needed to make use of OnNavigatedTo directly.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (App.ViewModel.GoHome) return;
...
}
A final use for BasePage just came up for DataHub now that we are working on the Silverlight-based “desktop” version. I am sharing (linking) as much of the code between projects as possible, including the code-behind for the XAML files. BasePage is implemented as project-specific, handing all plumbing differences (and inheriting from System.Windows.Controls.Page instead of Microsoft.Phone.Controls.PhoneApplicationPage). More on this in a future blog post (if there is any interest…)
Regards,
Jason
Thanks for sharing