Validate Entries using behaviours

This is based on a post here https://blog.xamarin.com/behaviors-in-xamarin-forms/ which is a little incomplete and had a couple of errors and some omissions.

The following example shows how to validate that an email address is valid

Create a new class that inherits from Behavior<T>. Make sure you don’t just inherit from Behavior as the code sample shows.

I used this, place in a folder and namespace of Behaviours (British English spelling!)

</p>
<p>using System;<br />
using System.Text.RegularExpressions;<br />
using Xamarin.Forms;</p>
<p>namespace MyApp.Behaviours<br />
{</p>
<p>public class EmailValidatorBehavior : Behavior&lt;Entry&gt;<br />
{<br />
    const string emailRegex = @&quot;^(?(&quot;&quot;)(&quot;&quot;.+?(?&amp;lt;!\\)&quot;&quot;@)|(([0-9a-z]((\.(?!\.))|[-!#\$%&amp;amp;'\*\+/=\?\^`\{\}\|~\w])*)(?&amp;lt;=[0-9a-z])@))&quot; +<br />
    @&quot;(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$&quot;;</p>
<p>    static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly(&quot;IsValid&quot;, typeof(bool), typeof(EmailValidatorBehavior), false);</p>
<p>    public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;</p>
<p>    protected override void OnAttachedTo(Entry bindable)<br />
    {<br />
        base.OnAttachedTo(bindable);<br />
        bindable.TextChanged += HandleTextChanged;<br />
    }</p>
<p>    protected override void OnDetachingFrom(Entry bindable)<br />
    {<br />
        base.OnDetachingFrom(bindable);<br />
        bindable.TextChanged -= HandleTextChanged;<br />
    }</p>
<p>    public bool IsValid<br />
    {<br />
        get { return (bool)base.GetValue(IsValidProperty); }<br />
        private set { base.SetValue(IsValidPropertyKey, value); }<br />
    }</p>
<p>    void HandleTextChanged(object sender, TextChangedEventArgs e)<br />
    {<br />
        IsValid = (Regex.IsMatch(e.NewTextValue, emailRegex, RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)));<br />
        ((Entry)sender).TextColor = IsValid ? Color.Default : Color.Red;<br />
    }</p>
<p>}<br />
}</p>
<p>

In the view add an xmlns for this namespace

<br />
xmlns:behaviours=&quot;clr-namespace:VCReportMobile.Behaviours&quot;<br />

Then assuming you have an Entry for email already, then extend it to

<br />
&lt;Entry Placeholder=&quot;Email&quot; Keyboard=&quot;Email&quot; Text=&quot;{Binding Email}&quot;&gt;<br />
                    &lt;Entry.Behaviors&gt;<br />
                        &lt;behaviours:EmailValidatorBehavior x:Name=&quot;emailValidator&quot;/&gt;<br />
                    &lt;/Entry.Behaviors&gt;<br />
                &lt;/Entry&gt;<br />

This makes a reference to the behaviour. Now when the Entry doesn’t contain a valid email the colour of the text in the Entry will change to red.

Now if you want to make this a bit clearer and place a label on the page that will say if the email is valid or not.

Add a label to the view.

<br />
&lt;Label Style=&quot;{Binding Source={x:Reference emailValidator}, Path=IsValid, Converter={StaticResource boolToStyleEmail}}&quot; /&gt;<br />

The Binding Source={x:Reference emailValidator} says to bind with an element that’s on the view already. The Path bit determines the property to bind to.
The converter we’ll get onto next.
What this does is take the boolean IsValid property and convert it into a Style. It seems a Style can amend text as well as formatting.

I placed the code into a folder/namespace of Classes, so I needed another xmlns in my view.

<br />
xmlns:classes=&quot;clr-namespace:VCReportMobile.Classes&quot;<br />

And the following 2 Style to flip between.

<br />
    &lt;ContentPage.Resources&gt;<br />
        &lt;ResourceDictionary&gt;</p>
<p>            &lt;Style x:Key=&quot;baseStyle&quot; TargetType=&quot;Label&quot;&gt;<br />
                &lt;Setter Property=&quot;HorizontalTextAlignment&quot; Value=&quot;Start&quot; /&gt;<br />
                &lt;Setter Property=&quot;FontSize&quot; Value=&quot;Micro&quot; /&gt;<br />
                &lt;Setter Property=&quot;FontAttributes&quot; Value=&quot;Italic&quot; /&gt;<br />
            &lt;/Style&gt;</p>
<p>            &lt;classes:BooleanToObjectConverter x:Key=&quot;boolToStyleEmail&quot; x:TypeArguments=&quot;Style&quot;&gt;<br />
                &lt;classes:BooleanToObjectConverter.FalseObject&gt;</p>
<p>                    &lt;Style TargetType=&quot;Label&quot; BasedOn=&quot;{StaticResource baseStyle}&quot;&gt;<br />
                        &lt;Setter Property=&quot;TextColor&quot; Value=&quot;#F44336&quot; /&gt;<br />
                        &lt;Setter Property=&quot;Text&quot; Value=&quot;Enter a valid email&quot; /&gt;<br />
                    &lt;/Style&gt;</p>
<p>                &lt;/classes:BooleanToObjectConverter.FalseObject&gt;</p>
<p>                &lt;classes:BooleanToObjectConverter.TrueObject&gt;</p>
<p>                   &lt;Style TargetType=&quot;Label&quot; BasedOn=&quot;{StaticResource baseStyle}&quot;&gt;<br />
                        &lt;Setter Property=&quot;TextColor&quot; Value=&quot;#4CAF50&quot; /&gt;<br />
                        &lt;Setter Property=&quot;Text&quot; Value=&quot;Your email looks good&quot; /&gt;<br />
                    &lt;/Style&gt;</p>
<p>                &lt;/classes:BooleanToObjectConverter.TrueObject&gt;</p>
<p>            &lt;/classes:BooleanToObjectConverter&gt;<br />
        &lt;/ResourceDictionary&gt;<br />
    &lt;/ContentPage.Resources&gt;<br />

Note that this must be placed within the ContentPage.Resources / ResourceDictionary. I failed to do this and had troubles running the app on my device.

The code that changes a boolean to objects is

<br />
namespace MyApp.Classes<br />
{<br />
  public   class BooleanToObjectConverter&lt;T&gt; : IValueConverter<br />
    {<br />
        public T FalseObject { set; get; }</p>
<p>        public T TrueObject { set; get; }</p>
<p>        public object Convert(object value, Type targetType,<br />
                              object parameter, CultureInfo culture)<br />
        {<br />
            return (bool)value ? this.TrueObject : this.FalseObject;<br />
        }</p>
<p>        public object ConvertBack(object value, Type targetType,<br />
                                  object parameter, CultureInfo culture)<br />
        {<br />
            return ((T)value).Equals(this.TrueObject);<br />
        }<br />
    }<br />
}<br />

See this post on how I disable a button until the entries pass validation.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.