简体   繁体   中英

How to fire TextChanged event on a Xamarin Forms entry field programmatically?

We have setup some Xamarin behavior for not null entry fields etc, this fires when the user makes a change to a field and we then changed the entry border color, red for invalid.

However, we'd also like to reuse this behaviors when a submit button is tapped.

So I need to fire the TextChanged event manually, any ideas how I can do this, now sure if it's possible?

public class NotEmptyEntryBehaviour : Behavior<Entry>
{
    protected override void OnAttachedTo(Entry bindable)
    {
        bindable.TextChanged += OnEntryTextChanged;
        base.OnAttachedTo(bindable);
    }

    protected override void OnDetachingFrom(Entry bindable)
    {
        bindable.TextChanged -= OnEntryTextChanged;
        base.OnDetachingFrom(bindable);
    }

    void OnEntryTextChanged(object sender, TextChangedEventArgs args)
    {
        if (args == null)
            return;

        var oldString = args.OldTextValue;
        var newString = args.NewTextValue;
    }
}

If you want an alternative you can use one of the pre-built validation behaviors that comes with Xamarin.CommunityToolkit package , like TextValidationBehavior (by specifying a Regexp) or any more specific derived ones (example NumericValidationBehavior ) that may fit your needs or even create a custom one by sub-classing ValidationBehavior .

It let you define custom styles for Valid and InValid states, but more important for the question has an async method called ForceValidate() .

Also the Flags property could be interesting.

NotEmptyEntryBehaviour seems closer to TextValidationBehavior with MinimumLenght=1

xaml

 <Entry Placeholder="Type something..." x:Name="entry">
        <Entry.Behaviors>
            <xct:TextValidationBehavior Flags="ValidateOnValueChanging"
                                        InvalidStyle="{StaticResource InvalidEntryStyle}"
                                        ValidStyle="{StaticResource ValidEntryStyle}"/>
        </Entry.Behaviors>
    </Entry>

Code

await (entry.Behaviors[0] as TextValidationBehavior)?.ForceValidate();

Docs

https://docs.microsoft.com/en-us/xamarin/community-toolkit/behaviors/charactersvalidationbehavior

Repo Samples

https://github.com/xamarin/XamarinCommunityToolkit/tree/main/samples/XCT.Sample/Pages/Behaviors

We have setup some Xamarin behavior for not null entry fields etc, this fires when the user makes a change to a field and we then changed the entry border color, red for invalid.

You can create custom Entry with behavior to get.

The first I'm going to do is to create a new control that inherits from Entry and will add three properties: IsBorderErrorVisible, BorderErrorColor, ErrorText.

public class ExtendedEntry : Entry
{
    public static readonly BindableProperty IsBorderErrorVisibleProperty =
        BindableProperty.Create(nameof(IsBorderErrorVisible), typeof(bool), typeof(ExtendedEntry), false, BindingMode.TwoWay);

    public bool IsBorderErrorVisible
    {
        get { return (bool)GetValue(IsBorderErrorVisibleProperty); }
        set
        {
            SetValue(IsBorderErrorVisibleProperty, value);
        }
    }

    public static readonly BindableProperty BorderErrorColorProperty =
        BindableProperty.Create(nameof(BorderErrorColor), typeof(Xamarin.Forms.Color), typeof(ExtendedEntry), Xamarin.Forms.Color.Transparent, BindingMode.TwoWay);

    public Xamarin.Forms.Color BorderErrorColor
    {
        get { return (Xamarin.Forms.Color)GetValue(BorderErrorColorProperty); }
        set
        {
            SetValue(BorderErrorColorProperty, value);
        }
    }

    public static readonly BindableProperty ErrorTextProperty =
    BindableProperty.Create(nameof(ErrorText), typeof(string), typeof(ExtendedEntry), string.Empty);

    public string ErrorText
    {
        get { return (string)GetValue(ErrorTextProperty); }
        set
        {
            SetValue(ErrorTextProperty, value);
        }
    }
}

Then creating custom render to android platform.

[assembly: ExportRenderer(typeof(ExtendedEntry), typeof(ExtendedEntryRenderer))]
namespace FormsSample.Droid
{
public class ExtendedEntryRenderer : EntryRenderer
{
    public ExtendedEntryRenderer(Context context) : base(context)
    {
    }
    protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
    {
        base.OnElementChanged(e);

        if (Control == null || e.NewElement == null) return;

        UpdateBorders();
    }

    protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);

        if (Control == null) return;

        if (e.PropertyName == ExtendedEntry.IsBorderErrorVisibleProperty.PropertyName)
            UpdateBorders();
    }

    void UpdateBorders()
    {
        GradientDrawable shape = new GradientDrawable();
        shape.SetShape(ShapeType.Rectangle);
        shape.SetCornerRadius(0);

        if (((ExtendedEntry)this.Element).IsBorderErrorVisible)
        {
            shape.SetStroke(3, ((ExtendedEntry)this.Element).BorderErrorColor.ToAndroid());
        }
        else
        {
            shape.SetStroke(3, Android.Graphics.Color.LightGray);
            this.Control.SetBackground(shape);
        }

        this.Control.SetBackground(shape);
    }

}

}

Finally, Creating an Entry Behavior, handle the error to provide ui feedback to the user when validation occurs

 public class EmptyEntryValidatorBehavior : Behavior<ExtendedEntry>
{
    ExtendedEntry control;
    string _placeHolder;
    Xamarin.Forms.Color _placeHolderColor;

    protected override void OnAttachedTo(ExtendedEntry bindable)
    {
        bindable.TextChanged += HandleTextChanged;
        bindable.PropertyChanged += OnPropertyChanged;
        control = bindable;
        _placeHolder = bindable.Placeholder;
        _placeHolderColor = bindable.PlaceholderColor;
    }

    void HandleTextChanged(object sender, TextChangedEventArgs e)
    {
        ExtendedEntry customentry = (ExtendedEntry)sender;
        if (!string.IsNullOrEmpty(customentry.Text))
        {
            ((ExtendedEntry)sender).IsBorderErrorVisible = false;
        }
        else
        {
            ((ExtendedEntry)sender).IsBorderErrorVisible = true;
        }
      
    }

    protected override void OnDetachingFrom(ExtendedEntry bindable)
    {
        bindable.TextChanged -= HandleTextChanged;
        bindable.PropertyChanged -= OnPropertyChanged;
    }

    void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == ExtendedEntry.IsBorderErrorVisibleProperty.PropertyName && control != null)
        {
            if (control.IsBorderErrorVisible)
            {
                control.Placeholder = control.ErrorText;
                control.PlaceholderColor = control.BorderErrorColor;
                control.Text = string.Empty;
            }

            else
            {
                control.Placeholder = _placeHolder;
                control.PlaceholderColor = _placeHolderColor;
            }

        }
    }
}

在此处输入图像描述

Update:

You can change custom entry's IsBorderErrorVisible in button.click, to call this from submit button.

 private void btn1_Clicked(object sender, EventArgs e)
    {
       
        if(string.IsNullOrEmpty(entry1.Text))
        {
            entry1.IsBorderErrorVisible = true;
        }
    }

<customentry:ExtendedEntry
            x:Name="entry1"
            BorderErrorColor="Red"
            ErrorText="please enter name!">
            <customentry:ExtendedEntry.Behaviors>
                <behaviors:EmptyEntryValidatorBehavior />
            </customentry:ExtendedEntry.Behaviors>
        </customentry:ExtendedEntry>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM