Search code examples
c#xamarinxamarin.formssyncfusion

How to simplify bindings that depend on each other?


I have an Entry that I want to give a red outline when the entry is empty. I'm using SyncFusion's SFTextInputLayout for my Entry and it has a property "HasError" that once it's set to true, it'll automatically highlight my entire in Red.

Here is the following XAML code for SFTextInputLayout

 <inputLayout:SfTextInputLayout Grid.Column="0" Hint="Phone Number" ContainerType="{StaticResource RepairOrderContainerType}" HasError="{Binding IsPhoneNumberError}" FocusedColor="{StaticResource AccentColor}" VerticalOptions="Center" HorizontalOptions="Start">
       <Entry Keyboard="Telephone" Style="{StaticResource TextInputStyle}" Text="{Binding PhoneNumber}"/>
 </inputLayout:SfTextInputLayout>

As you can see, I have two bindings that handles the text of the entry and another one to check if it has an error or not. While this solution works, it will get redundant pretty soon as the number of my entry fields grow. For every entry field I have, I need another boolean to cover its Error property as shown below.

  private string _phoneNumber;
    public string PhoneNumber
    {
        get => _phoneNumber;
        set
        {
            IsPhoneNumberError = string.IsNullOrWhiteSpace(value) ? true : false;
            this.RaiseAndSetIfChanged(ref _phoneNumber, _phoneNumber);
        }
    }

    private bool _isPhoneNumberError = false;
    public bool IsPhoneNumberError
    {
        get => _isPhoneNumberError;
        set
        {
            this.RaiseAndSetIfChanged(ref _isPhoneNumberError, value);
        }
    }

I'm wondering if there's any way to simplify this code. Thanks in advance!


Solution

  • One way of many to accomplish this is by creating a custom control with a behavior.

    create a custom control:

    public class MySfTextInputLayout : SfTextInputLayout
    {
    
        public MySfTextInputLayout ()
        {
            Behaviors.Add(new ShowErrorBehavior());
        }
        public bool HasErrors
        {
            get { return (bool)GetValue(HasErrorsProperty); }
            set { SetValue(HasErrorsProperty, value); }
        }
        public static readonly BindableProperty HasErrorsProperty =
            BindableProperty.Create(nameof(HasErrors), typeof(bool), typeof(MySfTextInputLayout ), false);
    
    }
    

    and the behavior:

    public class ShowErrorBehavior : Behavior<MySfTextInputLayout>
    {
        protected override void OnAttachedTo(MySfTextInputLayout entry)
        {
            entry.TextChanged += OnEntryTextChanged;
            base.OnAttachedTo(entry);
        }
        protected override void OnDetachingFrom(MySfTextInputLayout entry)
        {
            entry.TextChanged -= OnEntryTextChanged;
            base.OnDetachingFrom(entry);
        }
    
        void OnEntryTextChanged(object sender, TextChangedEventArgs args)
        {
            ((MySfTextInputLayout)sender).HasErrors = string.IsNullOrWhiteSpace(args.NewTextValue);
        }
    }
    

    The behavior will decide the validity of text for you, so you don't have to bind to another property just for that. Also take a look at the Validation API, you may want to add multiple rules for an entry to be valid:

    https://devblogs.microsoft.com/xamarin/validation-xamarin-forms-enterprise-apps/