Caliburn Micro WP7 and SL Toolkit TransitionFrames

Nov 7, 2010 at 10:58 PM
Edited Nov 7, 2010 at 11:00 PM

Hi,

I'm working on a project combining Caliburn Micro as my MVVM framework and using the newest release of the Toolkit for WP7. The Transitions seem stuttery and flicker a lot, sometimes the page flickers between navigation even without the transition frames.

In the same kind of project without Caliburn Micro (using no MVVM) framework, it seems to work smoothly and flawlessly.

Here's how I've done it anyway:

I've made it so the RootFrame is a TransitionFrame in the PhoneBootStrapper like so:

    /// <summary>
    /// Creates the root frame used by the application.
    /// </summary>
    /// <returns>The frame.</returns>
    protected virtual PhoneApplicationFrame CreatePhoneApplicationFrame( ) {
      return new TransitionFrame( );
    }

I have then added the following to my View XAML files:

    <toolkit:TransitionService.NavigationInTransition>
        <toolkit:NavigationInTransition>
            <toolkit:NavigationInTransition.Backward>
                <toolkit:TurnstileTransition Mode="BackwardIn"/>
            </toolkit:NavigationInTransition.Backward>
            <toolkit:NavigationInTransition.Forward>
                <toolkit:TurnstileTransition Mode="ForwardIn"/>
            </toolkit:NavigationInTransition.Forward>
        </toolkit:NavigationInTransition>
    </toolkit:TransitionService.NavigationInTransition>
    <toolkit:TransitionService.NavigationOutTransition>
        <toolkit:NavigationOutTransition>
            <toolkit:NavigationOutTransition.Backward>
                <toolkit:TurnstileTransition Mode="BackwardOut"/>
            </toolkit:NavigationOutTransition.Backward>
            <toolkit:NavigationOutTransition.Forward>
                <toolkit:TurnstileTransition Mode="ForwardOut"/>
            </toolkit:NavigationOutTransition.Forward>
        </toolkit:NavigationOutTransition>
    </toolkit:TransitionService.NavigationOutTransition>

 

You can find a barebones test project here:

http://tempsite.ia.geek.nz/CaliburnToolkitTransitions.zip

Any idea what would need to be changed to get this working for Caliburn Micro? Or smoother? Or what part of Caliburn Micro is causing this?

Any information and a good point in the right direction would be great.

 

 

Nov 9, 2010 at 1:16 AM

It looks like the content of the control that you are navigating to has not been loaded/initialised yet.  I have just overridden the TransitionFrame to do what the Navigation service does on OnNavigated and it seems like it has all gone away.  I am kind of thinking that the call to InitializeComponent should be in the before navigating, not post navigated.

    public class MyTransitionFrame : TransitionFrame
    {

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
        }

        protected override void OnContentChanged( object oldContent, object newContent )
        {
            //System.Diagnostics.Debugger.Break();
            ViewLocator.InitializeComponent( newContent );

            var viewModel = ViewModelLocator.LocateForView( newContent );
            if( viewModel == null )
                return;

            ViewModelBinder.Bind( viewModel, (DependencyObject)newContent, null );

            TryInjectQueryString( viewModel, newContent );

            var activator = viewModel as IActivate;
            if( activator != null )
                activator.Activate();

            base.OnContentChanged( oldContent, newContent  );
        }

        protected virtual void TryInjectQueryString( object viewModel, object view )
        {
            var page = view as Page;
            if( page == null )
                return;

            var viewModelType = viewModel.GetType();

            foreach( var pair in page.NavigationContext.QueryString )
            {
                var property = viewModelType.GetProperty( pair.Key );
                if( property == null )
                    continue;

                property.SetValue( viewModel, MessageBinder.CoerceValue( property.PropertyType, pair.Value ), null );
            }
        }

    }

Coordinator
Nov 9, 2010 at 2:07 AM

You're probably right. I noticed some similar bizarre behavior in my sample and guessed that it might be related to that. I'm wondering if there is any event I can hook into to call it at the right time or if we will just have to require code behinds for WP7 out-if-the-box and then just have a recipe that shows how to do it in your own application. Thoughts?

Nov 9, 2010 at 9:18 PM

I have been digging into the reflected code of the Frame control, seeing as how it is the one responsible for changing the content, and at this moment in time I cannot see anything blindingly obvious that would allow for the model first approach.

Coordinator
Nov 10, 2010 at 2:04 AM

That's a bummer. I'll try to look into this a bit further, but it looks like code-behinds are going to be required for view-first WP7 approaches with the nav framework. Maybe in a future version they will add some of the features from Silverlight. Then we can probably plug this stuff into the right place in the pipeline.

Nov 11, 2010 at 12:30 AM

I got it working by overiding the OnStartup method on the WP7Bootstrapper class:

 

        protected override void OnStartup(object sender, StartupEventArgs e)
        {
            RootFrame.Style = (Style)Application.Resources["mainFrameStyle"];
        }

 

Coordinator
Nov 11, 2010 at 12:42 AM

Can you describe a little more what your solution does?

Nov 16, 2010 at 1:10 AM
Edited Nov 16, 2010 at 1:55 AM

Some kind of recipe would be great, even if it is code behind. I don't mind it as a measure until it's sorted/if it is.

Got it sorted with the first solution posted anyway :) thanks guys.

I tried your solution shawncamp, but it didn't seem to work in my project, would be cool to know how you figured it out though.

Nov 19, 2010 at 2:41 AM

Rob, do you have a quick example of whay you mean?  Would I still be able to access the navigation services from my VMs?

Coordinator
Nov 19, 2010 at 1:18 PM

@schappel I think I'm misunderstanding the context of your question. Can you re-state it for me? Thanks!

Nov 21, 2010 at 10:11 AM

never mind, too much late night programming.  I for some reason had in my head that my VM would not get a INavigationService passed to it (and I was way wrong).

So, I just put together a quick sample using a View-First approach, and all seems to be functioning correctly, except after I nav from Main Page -> Second Page -> Main Page -> Second Page, the last navigation throw a NullReference exception when calling ActionMessage.Invoke. It seems like context has not been set or something.  I had a similar error with my latest WP7 app during testing today, where occasionaly the navigation framework hands me a null instead of the content.  I think I might just put a return if null and see if it goes away.

Coordinator
Nov 21, 2010 at 12:52 PM

If you can send me a repro of that, I would appreciate it. Thanks!

Nov 22, 2010 at 11:25 AM

I have uploaded a simple sample to here (http://bit.ly/dbkVx4).  It shows both the problems I found

Coordinator
Nov 22, 2010 at 3:08 PM

Schappel, please send me an email robertheisenberg at hotmail dot com  I have fixed your solution. There was a "bug" in CM due to differences in event ordering with TransitionFrame. See my latest commit. This fixes the problem. But, you had a number of other issues that I fixed as well. So, I'd like to email you your solution back with the changes. Basically, here's what I changed:

1. Removed all the code from the App.xaml.cs You had duplicate Frames defined. Everything that is done there is actually handled by the Bootstrapper.

2. Removed the Bind.Model attached properties from your views. The FrameAdapter sets all that up automatically. This was actually causing multiple instances of the the same object to be resolved and bound to your views.

3. Removed your AttachView overrides. Context will always be null for the default view. See my most recent article which describes multiple views over the same VM.

4. Removed your null checks against INavigationService. That should never be null. If it was, it's likely somehow related to 1 or 2 above.

5. Changed the FrameAdapter constructor invocation to use the fix I mentioned above.

Nov 22, 2010 at 9:34 PM

Hi Rob,

Nice work.  I grabbed the latest change set (and removed the boiler plate code) and it works like a treat.  After my latest app makes it through the certification process, I will have to update it to include the page transitions (which I removed).

I have sent you an email, but I guess you have pretty much explained it in your previous post.

Cheers,

Scott