.NET MAUI Community Toolkit

Enhancing your .NET MAUI development

Creating Custom Effects

Custom Effects in the .NET MAUI Community Toolkit allow you to extend the rendering capabilities of your application by applying platform-specific logic to your UI elements. This is particularly useful for implementing visual enhancements or behaviors that are not directly supported by the standard .NET MAUI controls.

What are Custom Effects?

Effects are a way to attach custom rendering logic to any element in .NET MAUI. They are defined in shared code and then implemented in platform-specific projects. This allows you to write common code for your effects and leverage platform-specific APIs for optimal performance and integration.

When to Use Custom Effects?

Creating a Custom Effect

The process of creating a custom effect involves two main parts:

  1. Defining the Effect in Shared Code: This involves creating a class that inherits from RoutingEffect or PlatformEffect. For most common scenarios, RoutingEffect is sufficient.
  2. Implementing the Effect on Each Platform: For each target platform (Android, iOS, Windows, macOS), you'll create a class that inherits from PlatformEffect and applies the native rendering logic.

Step 1: Define the Effect in Shared Code

Let's create a simple custom effect that changes the background color of an element.

Shared Code (e.g., EffectBase/BackgroundColorEffect.cs)


using Microsoft.Maui.Controls;

namespace CommunityToolkit.Maui.Effects
{
    public class BackgroundColorEffect : RoutingEffect
    {
        public static readonly BindableProperty BackgroundColorProperty =
            BindableProperty.CreateAttached("BackgroundColor", typeof(Color), typeof(BackgroundColorEffect), null,
                propertyChanged: OnBackgroundColorChanged);

        public static Color GetBackgroundColor(BindableObject view)
        {
            return (Color)view.GetValue(BackgroundColorProperty);
        }

        public static void SetBackgroundColor(BindableObject view, Color value)
        {
            view.SetValue(BackgroundColorProperty, value);
        }

        static void OnBackgroundColorChanged(BindableObject bindable, object oldValue, object newValue)
        {
            if (bindable is VisualElement element)
            {
                // This is where you would typically send a message or trigger logic
                // that the platform-specific implementations listen for.
                // For simplicity here, we'll rely on the platform to read the property.
            }
        }

        public BackgroundColorEffect() : base("CommunityToolkit.Maui.Effects.BackgroundColorEffect")
        {
        }
    }
}
                

Step 2: Implement the Effect on Each Platform

Android:

Android Implementation (e.g., Effects/Android/BackgroundColorEffect.cs)


using Android.Graphics;
using Android.Widget;
using CommunityToolkit.Maui.Effects;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Graphics;
using Color = Microsoft.Maui.Graphics.Color;

[assembly: ExportEffect(typeof(CommunityToolkit.Maui.Effects.Platform.BackgroundColorEffect), nameof(BackgroundColorEffect))]
namespace CommunityToolkit.Maui.Effects.Platform
{
    public class BackgroundColorEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            UpdateBackgroundColor();
        }

        protected override void OnDetached()
        {
            // Clean up resources if necessary
        }

        protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)
        {
            base.OnElementPropertyChanged(args);

            if (args.PropertyName == BackgroundColorEffect.BackgroundColorProperty.PropertyName)
            {
                UpdateBackgroundColor();
            }
        }

        void UpdateBackgroundColor()
        {
            var mauiColor = BackgroundColorEffect.GetBackgroundColor(Element);
            if (mauiColor != null)
            {
                var androidColor = mauiColor.ToAndroid();
                if (Control != null)
                {
                    Control.SetBackgroundColor(androidColor);
                }
                else if (Container != null) // For elements like Layouts
                {
                    Container.SetBackgroundColor(androidColor);
                }
            }
            else
            {
                if (Control != null)
                {
                    Control.SetBackgroundColor(Android.Graphics.Color.Transparent);
                }
                else if (Container != null)
                {
                    Container.SetBackgroundColor(Android.Graphics.Color.Transparent);
                }
            }
        }
    }
}
                

iOS:

iOS Implementation (e.g., Effects/iOS/BackgroundColorEffect.cs)


using CommunityToolkit.Maui.Effects;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Platform;
using UIKit;
using Color = Microsoft.Maui.Graphics.Color;

[assembly: ExportEffect(typeof(CommunityToolkit.Maui.Effects.Platform.BackgroundColorEffect), nameof(BackgroundColorEffect))]
namespace CommunityToolkit.Maui.Effects.Platform
{
    public class BackgroundColorEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            UpdateBackgroundColor();
        }

        protected override void OnDetached()
        {
            // Clean up resources if necessary
        }

        protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)
        {
            base.OnElementPropertyChanged(args);

            if (args.PropertyName == BackgroundColorEffect.BackgroundColorProperty.PropertyName)
            {
                UpdateBackgroundColor();
            }
        }

        void UpdateBackgroundColor()
        {
            var mauiColor = BackgroundColorEffect.GetBackgroundColor(Element);
            if (mauiColor != null)
            {
                var uiColor = mauiColor.ToUIColor();
                if (Control != null)
                {
                    Control.BackgroundColor = uiColor;
                }
                else if (Container != null) // For elements like Layouts
                {
                    Container.BackgroundColor = uiColor;
                }
            }
            else
            {
                if (Control != null)
                {
                    Control.BackgroundColor = UIColor.Clear;
                }
                else if (Container != null)
                {
                    Container.BackgroundColor = UIColor.Clear;
                }
            }
        }
    }
}
                

Windows:

Windows Implementation (e.g., Effects/Windows/BackgroundColorEffect.cs)


using CommunityToolkit.Maui.Effects;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Platform;
using Windows.UI;
using Windows.UI.Xaml.Media;
using Color = Microsoft.Maui.Graphics.Color;

[assembly: ExportEffect(typeof(CommunityToolkit.Maui.Effects.Platform.BackgroundColorEffect), nameof(BackgroundColorEffect))]
namespace CommunityToolkit.Maui.Effects.Platform
{
    public class BackgroundColorEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            UpdateBackgroundColor();
        }

        protected override void OnDetached()
        {
            // Clean up resources if necessary
        }

        protected override void OnElementPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)
        {
            base.OnElementPropertyChanged(args);

            if (args.PropertyName == BackgroundColorEffect.BackgroundColorProperty.PropertyName)
            {
                UpdateBackgroundColor();
            }
        }

        void UpdateBackgroundColor()
        {
            var mauiColor = BackgroundColorEffect.GetBackgroundColor(Element);
            if (mauiColor != null)
            {
                var windowsColor = mauiColor.ToWindowsColor();
                var brush = new SolidColorBrush(windowsColor);
                if (Control != null)
                {
                    Control.Background = brush;
                }
                else if (Container != null) // For elements like Layouts
                {
                    Container.Background = brush;
                }
            }
            else
            {
                if (Control != null)
                {
                    Control.Background = null;
                }
                else if (Container != null)
                {
                    Container.Background = null;
                }
            }
        }
    }
}
                
Note: For a production-ready effect, you would typically use Dependency Injection and the IEffect interface for more robust communication between shared code and platform implementations. The RoutingEffect approach shown here is a simplified illustration.

Step 3: Apply the Effect in XAML

Once you have defined and implemented your custom effect, you can apply it to any VisualElement in your XAML markup.

Your Page XAML


<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:effects="clr-namespace:CommunityToolkit.Maui.Effects;assembly=CommunityToolkit.Maui.Core"
             x:Class="YourApp.MyPage">

    <StackLayout Padding="20">
        <Label Text="This Label has a custom background!"
               HorizontalOptions="Center"
               VerticalOptions="Center"
               Padding="10"
               effects:BackgroundColorEffect.BackgroundColor="LightBlue" />

        <Button Text="This Button also has a custom background"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Margin="20,0"
                effects:BackgroundColorEffect.BackgroundColor="LightGreen" />
    </StackLayout>
</ContentPage>
                

Step 4: Apply the Effect in C#

You can also apply effects programmatically in your C# code.

Your Page C# Code-Behind


using CommunityToolkit.Maui.Effects;
using Microsoft.Maui.Controls;

// ... inside your page class

public MyPage()
{
    InitializeComponent();

    var myLabel = new Label
    {
        Text = "Programmatic Effect!",
        HorizontalOptions = LayoutOptions.Center,
        VerticalOptions = LayoutOptions.Center,
        Padding = 10
    };

    BackgroundColorEffect.SetBackgroundColor(myLabel, Colors.Orange);
    // You would add this to your layout like:
    // Content = new StackLayout { Children = { myLabel } };
}
                

Advanced Usage and Considerations

Custom Effects are a powerful tool in the .NET MAUI Community Toolkit, enabling you to create truly unique and native-feeling user experiences across all your target platforms.