Create Custom Transitions

The RadTransitionControl provides you with several built-in transition effects, but you are allowed to create your custom ones by using the Transition Effects API. This tutorial will explain you the steps, needed to create a custom transition. Here they are:

Create Shader Effects

The Shader Effects are written in the HLSL language and get compiled via the DirectX library. To learn more about creating and compiling Shader Effects read this MSDN topic.

There is also a library for sample HLSL effects for WPF and Silverlight available. There you can find a list of ready for use Shader Effects.

Wrap Shader Effects within Transition Effects

After getting your .ps shader effect file, the next step is to create a Transition Effect class which wraps the Shader Effect. In this tutorial, a CircleRevealTransitionEffect will be used.

The class that wraps the shader effect should inherit the BaseTransitionEffect class and you should override its LoadShader() method. Here is a sample code:

public class CircleRevealTransitionEffect : BaseTransitionEffect 
{ 
    protected override PixelShader LoadShader() 
    { 
        return new PixelShader(); 
    } 
} 

In the override for the LoadShader() method you have to create a PixelShader instance and link it to the Shader Effect. Here it is:

Note the PackUri() method of the TransitionEffect class. It builds an absolute path to the Shader Effect file based on the parameter T that you've passed and the relative path passed as an argument. The first part of the absolute path is the assembly in which the shader effect file is placed. This is the assembly, in which the T type is located. For example, if the class CircleRevealTransitionEffect is placed in the CustomTransitions assembly, the first part of the Uri will be "/CustomTransitions;component/". The relative path passed to the method will be then concatenated to it - "/CustomTransitions;component/CustomTransitions/CircleRevealTransitionEffect.ps".

public class CircleRevealTransitionEffect : BaseTransitionEffect 
{ 
    protected override PixelShader LoadShader() 
    { 
        PixelShader pixelShader = new PixelShader(); 
        pixelShader.UriSource = TransitionEffect.PackUri<CircleRevealTransitionEffect>("CustomTransitions/CircleRevealTransitionEffect.ps"); 
        return pixelShader; 
    } 
} 

Wrap Transition Effects within Transition Providers

As the Transition is of type TransitionProvider, you have to wrap your Transition Effect class inside a class that inherits the Transition Provider.

public class CircleRevealTransition : ShaderTransitionProvider 
{ 
} 

In it you have to override the CreateTransitionEffect() method and return an instance of your Transition Effect class.

public class CircleRevealTransition : ShaderTransitionProvider 
{ 
    protected override TransitionEffect CreateTransitionEffect() 
    { 
        return new CircleRevealTransitionEffect(); 
    } 
} 

Pass Parameters to the Shader Effect

The Shader Effect can also have some constants that can be passed through the wrapper. For example, the previously used CircleRevealTransitionEffect accepts a fuzzy amount constant, which value can make the transition smoother.

In order to pass arguments to the Shader Effect you must be familiar with it. It is important to pass the correct constants with the correct values.

In order to pass the fuzzy amount constant create an appropriate DependencyProperty in your CircleRevealTransitionEffect class.

public static readonly DependencyProperty FuzzyAmountProperty = 
    DependencyProperty.Register("FuzzyAmount", 
                                    typeof(double), 
                                    typeof(CircleRevealTransitionEffect), 
                                    new PropertyMetadata(0.1, ShaderEffect.PixelShaderConstantCallback(1))); 
public double FuzzyAmount 
{ 
    get 
    { 
        return (double)this.GetValue(FuzzyAmountProperty); 
    } 
    set 
    { 
        this.SetValue(FuzzyAmountProperty, value); 
    } 
} 

In order to link the DependencyProperty with the appropriate Shader Effect constant you have to use the PixelShaderConstantCallback() static method of the ShaderEffect class. For its parameter you have to pass the index of the constant in the context of the Shader Effect. In this case the fuzzy amount is the first and the only constant that can be passed to the effect. If you have more than one constant just increment the index for the next ones (2, 3, 4 etc).

You also have to force an update of the Shader Effect constant, when your TransitionEffect class is instantiated. This ensures that the effect's constant has evaluated the default value of the dependency property, in case the FuzzyAmountProperty doesn't get set. This can be done in the constructor via the UpadteShaderValue() method of the base BaseTransitionEffect class.

public CircleRevealTransitionEffect() 
{ 
    base.UpdateShaderValue(FuzzyAmountProperty); 
} 

The next step is to add a FuzzyAmount property in the CircleRevealTransition class, so you can pass the constants via the Transition instance.

public double FuzzyAmount 
{ 
    get; 
    set; 
} 

In order to pass the value of the FuzzyAmount to the CircleRevealTransitionEffect use the override for the CreateTransitionEffect() method.

protected override ShaderEffect CreateTransitionEffect() 
{ 
    CircleRevealTransitionEffect effect = new CircleRevealTransitionEffect(); 
    effect.FuzzyAmount = this.FuzzyAmount; 
    return effect; 
} 

Use Custom Transitions

In order to use the custom transition that you have just created, you have to declare the namespace in which the CircleRevealTransition class is located. For example:

xmlns:customTransitions="clr-namespace:Controls.CustomTransitions;assembly=CustomTransitions" 

Now you can use it as any of the built-in transition effects.

<telerik:RadTransitionControl x:Name="radTransitionControl"> 
    <telerik:RadTransitionControl.Transition> 
        <customTransitions:CircleRevealTransition FuzzyAmount="0.2" /> 
    </telerik:RadTransitionControl.Transition> 
</telerik:RadTransitionControl> 

See Also

In this article