Transitions - How do I skip the null view?

Topics: Prism v2 - Silverlight 3, Prism v2 - WPF 3.5
Feb 27, 2010 at 2:31 AM

My transitions framework works on the content change of a content based control (to re-write to work otherwise is a non-starter there's too much code that relies on this structure). It transitions the old to new content on the contentchanged method override. However the current behavior of Composite/Prism sets the content property of a region content control to null before setting it to the new view value. This causes the transition to animate to a null / blank view then transition from the blank view to the new view, which as you can imagine looks pretty terrible. The closest I've gotten to avoid this is by writing a custom animatedcontentcontrol that overrides oncontentchanged and ignores null content, the problem with this solution is that it breaks the .Remove functionality of a region manager.

I have tried leveraging custom RegionBehaviors, and RegionAdapters but I can't seem to find the method override or event hook I need override to view change behavior of going to null content before new content when .Activate is called.

Any tips on how to solve this?

Mar 1, 2010 at 2:11 PM
Edited Mar 1, 2010 at 2:15 PM

Ok, I was able to solve this issue, the gist of it was that I:

1.) Created a new region type and called it AnimatedSingleActiveRegion, it's identical to SingleActiveRegion except I changed the Activate override to deactivate the old view AFTER activating the new view:

 

public override void Activate(object view)
{
     object currentActiveView = ActiveViews.FirstOrDefault();

     base.Activate(view);

     if (currentActiveView != null && currentActiveView != view && this.Views.Contains(currentActiveView))
     {
          base.Deactivate(currentActiveView);
     }
}

 

2.) Created a new region adapter, identical to the ContentControlRegionAdapter named AnimatedContentControlRegionAdapter. This adapts a custom control I created that inherits from ContentControl named AnimatedContentControl. The create region override returns a region of type AnimatedSingleActiveRegion.

3.) In my bootstrapper I added a mapping for the new region adapter.

 

protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
{
     RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();
			
     mappings.RegisterMapping(typeof(AnimatedContentControl), Container.Resolve<AnimatedContentControlRegionAdapter>());
        
return
mappings; }

 

4.) My AnimatedContentControl custom control inherits from Content Control and the root element for its default style control template is a TransitionElement from the Transitionals CodePlex project. The default style (generic.xaml) of the control looks like this:

 

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:Mass.Infrastructure.Controls"
                    xmlns:transc="clr-namespace:Transitionals.Controls;assembly=Transitionals"
                    xmlns:transt="clr-namespace:Transitionals.Transitions;assembly=Transitionals"
                    xmlns:trans="clr-namespace:Transitionals;assembly=Transitionals"
                    xmlns:refl="clr-namespace:System.Reflection;assembly=mscorlib">

	<Style TargetType="local:AnimatedContentControl">
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="local:AnimatedContentControl">
					<transc:TransitionElement x:Name="TransitionBox">
						<transc:TransitionElement.Transition>
							<transt:RotateTransition Angle="45" />
						</transc:TransitionElement.Transition>
					</transc:TransitionElement>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>

</ResourceDictionary>

 

5.) The code for the AnimatedContentControl looks like this:

 

public class AnimatedContentControl : ContentControl
    {
        private const string EmptyPendingContent = "AnimatedContentControlEmptyState";
        private bool _isInitialLoad = true;
        private object _pendingContent = EmptyPendingContent;
        private TransitionElement _transitionBox;


        public AnimatedContentControl()
        {
            DefaultStyleKey = typeof (AnimatedContentControl);

            ApplyTemplate();
        }

        public override void OnApplyTemplate()
        {
            _transitionBox = (TransitionElement) GetTemplateChild("TransitionBox");

            base.OnApplyTemplate();
        }

        protected override void OnContentChanged(object oldContent, object newContent)
        {
            if (_transitionBox != null)
            {               
                if (_transitionBox.IsTransitioning)
                {
                    _pendingContent = newContent;
                    return;
                }


                _isInitialLoad = false;


                TransitionEventHandler[] @transitionEndedDelegateCopy = {null};
                TransitionEventHandler transitionEndedDelegate = delegate
                                                                     {
                                                                         _transitionBox.TransitionEnded -=
                                                                             @transitionEndedDelegateCopy[0];


                                                                         if (!(_pendingContent is string) ||
                                                                             (string) _pendingContent !=
                                                                             EmptyPendingContent)
                                                                         {
                                                                             object pendingContent = _pendingContent;
                                                                             _pendingContent = EmptyPendingContent;


                                                                             OnContentChanged(newContent,
                                                                                              pendingContent);
                                                                         }
                                                                     };

                @transitionEndedDelegateCopy[0] = transitionEndedDelegate;
                _transitionBox.TransitionEnded += transitionEndedDelegate;

                _transitionBox.Content = newContent;
            }
        }
    }

 

 

May 7, 2010 at 8:45 AM
Dear JoeGershgorin Can you pl provide me the code with example in Vb.Net Thanks Jignesh
May 12, 2010 at 7:37 PM

JoeGershgorin, I have followed your example here but stil see the blank page in between the translations, is the part where you override the Active method in  suppose to supress the AnimatedSingleActiveRegion blank page? The Active method is only being fired once per transition for me.

Oct 8, 2010 at 12:11 AM

2Joe: it's awesome!

2Ambog36: You probably derived AnimatedSingleActiveRegion from SingleActiveRegion instead of Region.