Xamarin.Forms - How to Use BindableProperty In Effects

 
 
 
(The Blog about change Image color at Run time using Tint Color)
 

Introduction

 
Xamarin.Forms code runs on multiple platforms, each of which has its own filesystem. This means that reading and writing files are most easily done using the native file APIs on each platform. Alternatively, embedded resources are a simpler solution to distribute data files with an app.
 
Tint Image
 
TintImage is used for change image color at runtime with the help of effects, you can achieve with custom render also. Tint images are mainly used to reduce the usage of the images.
 
BindableProperty
 
Attached properties can be used to define effect parameters that respond to runtime property changes. This article demonstrates using attached properties to pass parameters to an effect and changing a parameter at runtime.
 
Prerequisites
  • Visual Studio 2017 or later (Windows or Mac)

Setting up a Xamarin.Forms Project

 
Start by creating a new Xamarin.Forms project. You will learn more by going through the steps yourself.
 
Create a new or existing Xamarin forms (.Net standard) Project with Android and iOS Platform.
 
 
 

The Problem

 
We are not able to create a BindableProperty in Effect.
 

Solution

 
Create Effect
 
Now, Create a TintImage class inherit from RoutingEffect for Change image color.
 
TintImage.cs
  1. public class TintImage: RoutingEffect  
  2.     {  
  3.         public Color TintColor { getprivate set; }  
  4.         public TintImage(Color color) : base($"MyCompany.{nameof(TintImage)}")  
  5.         {  
  6.             TintColor = color;  
  7.         }  
  8.           
  9.     }  
Create Static Class
 
Here, I'm going to create a Static Class to create a BindableProperty on my Effect.
 
TintImageEffect.cs
  1. public static class TintImageEffect  
  2.     {  
  3.         public static BindableProperty TintColorProperty =  
  4.             BindableProperty.CreateAttached("TintColor",  
  5.                                             typeof(Color),  
  6.                                             typeof(TintImageEffect),  
  7.                                             Color.Default,  
  8.                                             propertyChanged: OnTintColorPropertyPropertyChanged);  
  9.   
  10.         public static Color GetTintColor(BindableObject element)  
  11.         {  
  12.             return (Color)element.GetValue(TintColorProperty);  
  13.         }  
  14.   
  15.         public static void SetTintColor(BindableObject element, Color value)  
  16.         {  
  17.             element.SetValue(TintColorProperty, value);  
  18.         }  
  19.   
  20.   
  21.         static void OnTintColorPropertyPropertyChanged(BindableObject bindable, object oldValue, object newValue)  
  22.         {  
  23.             AttachEffect(bindable as Image, (Color)newValue);  
  24.         }  
  25.   
  26.         static void AttachEffect(Image element, Color color)  
  27.         {  
  28.             var effect = element.Effects.FirstOrDefault(x => x is TintImage) as TintImage;  
  29.   
  30.             if (effect != null)  
  31.             {  
  32.                 element.Effects.Remove(effect);  
  33.             }  
  34.   
  35.             element.Effects.Add(new TintImage(color));  
  36.         }  
  37.   
  38.     }  
Android Implementation
 
Here, implement Platform Effects for TintImage at Runtime.
 
TintImageImpl.cs
  1. [assembly: ExportEffect(typeof(TintImageImpl), nameof(XamarinStudy.Common.Controls.TintImage))]  
  2. namespace XamarinStudy.Droid.Effects  
  3. {  
  4.     public class TintImageImpl: PlatformEffect  
  5.     {  
  6.         protected override void OnAttached()  
  7.         {  
  8.             try  
  9.             {  
  10.                 var effect = (XamarinStudy.Common.Controls.TintImage)Element.Effects.FirstOrDefault(e => e is XamarinStudy.Common.Controls.TintImage);  
  11.   
  12.                 if (effect == null || !(Control is ImageView image))  
  13.                     return;  
  14.   
  15.                 var filter = new PorterDuffColorFilter(effect.TintColor.ToAndroid(), PorterDuff.Mode.SrcIn);  
  16.                 image.SetColorFilter(filter);  
  17.             }  
  18.             catch (Exception ex)  
  19.             {  
  20.                   
  21.             }  
  22.         }  
  23.   
  24.         protected override void OnDetached() { }  
  25.     }  
  26. }  
iOS Implementation
 
Here, implement Platform Effects for TintImage at Runtime.
 
TintImageImpl.cs
  1. [assembly: ExportEffect(typeof(XamarinStudy.iOS.Effects.TintImageImpl), nameof(TintImage))]  
  2. namespace XamarinStudy.iOS.Effects  
  3. {  
  4.     public class TintImageImpl: PlatformEffect  
  5.     {  
  6.         protected override void OnAttached()  
  7.         {  
  8.             try  
  9.             {  
  10.                 var effect = (XamarinStudy.Common.Controls.TintImage)Element.Effects.FirstOrDefault(e => e is XamarinStudy.Common.Controls.TintImage);  
  11.   
  12.                 if (effect == null || !(Control is UIImageView image))  
  13.                     return;  
  14.   
  15.                 image.Image = image.Image.ImageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate);  
  16.                 image.TintColor = effect.TintColor.ToUIColor();  
  17.             }  
  18.             catch (Exception ex)  
  19.             {  
  20.             }  
  21.         }  
  22.   
  23.         protected override void OnDetached() { }  
  24.     }  
  25. }  
Create ViewModel
 
Now, create a Property for binding the color to View. Then, create a ChangeColorCommand for changing the image color at runtime.
 
MainPageViewModel.cs
  1. public class MainPageViewModel:BaseViewModel  
  2.     {  
  3.         #region Fields  
  4.   
  5.         private Command _changeColorCommand;  
  6.   
  7.         private Color _imageColor;  
  8.         #endregion  
  9.  
  10.         #region Constructor  
  11.   
  12.         public MainPageViewModel()  
  13.         {  
  14.             _imageColor = Color.Gray;  
  15.         }  
  16.  
  17.         #endregion  
  18.  
  19.         #region Properties  
  20.   
  21.         public Color ImageColor  
  22.         {  
  23.             get { return _imageColor; }  
  24.             set { Set(() => ImageColor, ref _imageColor, value); }  
  25.         }  
  26.   
  27.         public Command ChangeColorCommand  
  28.         {  
  29.             get  
  30.             {  
  31.                 return _changeColorCommand ?? (_changeColorCommand = new Command(() =>  
  32.                 {  
  33.                     if(this.ImageColor==Color.Black)  
  34.                     {  
  35.                         this.ImageColor = Color.Gray;  
  36.                     }  
  37.                     else  
  38.                     {  
  39.                         this.ImageColor = Color.Black;  
  40.                     }  
  41.                 }));  
  42.             }  
  43.         }  
  44.  
  45.         #endregion  
  46.   
  47.     }  
Consuming the TintImage
 
Now, use the TintImage effect in your XAML code.
 
MainPage.xaml
  1. <?xml version="1.0" encoding="utf-8" ?>    
  2. <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"    
  3.              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"    
  4.              xmlns:d="http://xamarin.com/schemas/2014/forms/design"    
  5.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    
  6.              mc:Ignorable="d"    
  7.              xmlns:behaviors="clr-namespace:XamarinStudy.Common.Behaviors"    
  8.              xmlns:converters="clr-namespace:XamarinStudy.Common.Converters"    
  9.              xmlns:Effects="clr-namespace:XamarinStudy.Common.Controls"    
  10.              x:Class="XamarinStudy.MainPage" Title="Effects">    
  11.        
  12.    <StackLayout Margin="10,30,10,0" Spacing="20">    
  13.         <Image Source="banner.png"/>    
  14.         <Image Source="favicon.png" Effects:TintImageEffect.TintColor="{Binding ImageColor}">    
  15.          </Image>    
  16.             
  17.    </StackLayout>    
  18.         
  19. </ContentPage>    
Click the "Play" button to try it out.
 
 
 
Wow, It's working.
 
I hope you have understood how to use BindableProperty Effects in Xamarin.Forms.
 
Thanks for reading. Please share your comments and feedback. Happy Coding :)