fabulous-dev / Fabulous

Declarative UI framework for cross-platform mobile & desktop apps, using MVU and F# functional programming
https://fabulous.dev
Apache License 2.0
1.14k stars 121 forks source link

Entry behaviour sample #827

Closed sandeep-eroad closed 3 years ago

sandeep-eroad commented 3 years ago

Is there a sample showing how to use Entry behaviour to disallow entering some characters in Entry control?

SergejDK commented 3 years ago

@sandeep-eroad

I tested behavior and entry with a passwordchecker but I think you can change the little part and then you can disallow specific characters.

Here is the code I come up with:

module TestEntryBehavior =
    open Xamarin.Forms
    type EntryBehavior() =
        inherit Xamarin.Forms.Behavior<Entry>()

        let onTextChanged(sender: obj, args: TextChangedEventArgs) =
            let passwordRegex = @"^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$"
            let IsValid = (System.Text.RegularExpressions.Regex.IsMatch(args.NewTextValue, passwordRegex))
            match IsValid with
            | true -> (sender :?> Entry).TextColor <- Color.Default
            | false -> (sender :?> Entry).TextColor <- Color.Red

        override this.OnAttachedTo(entry: Entry) =
            entry.TextChanged.AddHandler(fun x y -> onTextChanged(x,y))
            base.OnAttachedTo(entry)

        override this.OnDetachingFrom(entry: Entry) =
            entry.TextChanged.RemoveHandler(fun x y -> onTextChanged(x,y))
            base.OnDetachingFrom(entry)

    type Fabulous.XamarinForms.View with 

        static member inline EntryBehavior() = 

            // Get the attributes for the base element. The number is the expected number of attributes.
            // You can add additional base element attributes here if you like
            let attribCount = 0
            let attribs = ViewBuilders.BuildView(attribCount) 

            // The incremental update method
            let update (prevOpt: ViewElement voption) (source: ViewElement) (target: Xamarin.Forms.Behavior) = 
                ViewBuilders.UpdateBindableObject(prevOpt, source, target)

            let updateAttachedProperties propertyKey prevOpt source targetChild =
                ViewBuilders.UpdateBindableObjectAttachedProperties(propertyKey, prevOpt, source, targetChild)

            ViewElement.Create<EntryBehavior>(EntryBehavior, update, updateAttachedProperties, attribs)

And then you can use it like the following:

View.Entry(
                    text = entryText,
                    horizontalOptions = LayoutOptions.CenterAndExpand,
                    behaviors = [View.EntryBehavior()], // behavior used here
                    textChanged = (fun args -> dispatch (TextChanged(args.OldTextValue, args.NewTextValue))), 
                    completed = fun text -> dispatch (EntryEditCompleted text)
                )
TimLariviere commented 3 years ago

I've opened a feature request for better integration of behaviors in Fabulous: https://github.com/fsprojects/Fabulous/issues/832. In the meantime, the solution of @SergejDK is the recommended way.

sandeep-eroad commented 3 years ago

Thanks @SergejDK for the sample code.

sandeep-eroad commented 3 years ago

Hi @SergejDK , I tried your solution but I want to change the text - trim spaces, and as soon as I do that the handler is called recursively and is stuck in a loop.

sandeep-eroad commented 3 years ago

@SergejDK - It was only an issue while debugging, it seems to work fine if not debugging.