Forum Xamarin.Forms

Xamarin Forms how to add behaviors to custom control

DimitrisMylonasDimitrisMylonas USMember ✭✭✭

I have created a custom control,which is a ContentView with a Label and an Entry

The xaml of the custom controls looks like this:

<Label Text="{Binding Source={x:Reference ValidationControl}, Path=Caption}"/>
<Entry Text="{Binding Source={x:Reference ValidationControl}, Path=Value, Mode=TwoWay}" />

The code behind of the custom control looks like this:

public static readonly BindableProperty CaptionProperty = BindableProperty.Create(
    nameof(Caption), typeof(string), typeof(ValidationEntry), default(string));

public string Caption
{
    get => (string)GetValue(CaptionProperty);
    set => SetValue(CaptionProperty, value);
}

public static readonly BindableProperty ValueProperty = BindableProperty.Create(
    nameof(Value), typeof(string), typeof(ValidationEntry), default(string));

public string Value
{
    get => (string)GetValue(ValueProperty);
    set => SetValue(ValueProperty, value);
}

I’m using the custom control in the following way

<controls:ValidationEntry Caption=”Name:” Value="{Binding FullName, Mode=TwoWay}" />

My question is how to add behaviors to the custom control?
I would like to add them in the place that I’m using the control. i.e.

<controls:ValidationEntry Caption="Name:"
                          Value="{Binding FullName, Mode=TwoWay}">
    <controls:ValidationEntry.EntryBehaviors>
        <behaviors:EntryLengthValidatorBehavior IgnoreSpaces="True"/>
    </controls:ValidationEntry.EntryBehaviors>
</controls:ValidationEntry>

Answers

  • ColeXColeX Member, Xamarin Team Xamurai

    What's the problem you're facing ? What exactly do you want to achieve ?

  • DimitrisMylonasDimitrisMylonas USMember ✭✭✭

    Add behaviors to the custom control that I can apply to the Entry.
    I wasn't able to find a way to populate the IList<Behaviors> of the Entry inside the custom control by adding the behaviors in the custom control.

  • ColeXColeX Member, Xamarin Team Xamurai

    Create behavior for your custom control , and find the Entry inside it ..

    class CustomBehavior : Behavior<ValidationEntry>
        {
            protected override void OnAttachedTo(ValidationEntry view)
            {
                StackLayout stack = view.Content as StackLayout;
                Entry e = stack.Children[0] as Entry;
                //handle the logic
    
                base.OnAttachedTo(view);
            }
        }
    
  • DimitrisMylonasDimitrisMylonas USMember ✭✭✭
    edited July 2019

    So you mean, that there is no way to add behaviors to my custom control like I do with an Entry?
    You mean, that if I have a behavior for an Entry and I need it also for my custom control then I cannot reuse it and I should create a different behavior doing the same thing but for my custom control?
    You mean that if I have another custom control with 2 Entries (i.e. phone number with National prefix and the phone number) and I need the same behavior then I should create a third for that particular custom control?

  • ColeXColeX Member, Xamarin Team Xamurai
    edited July 2019

    Why don't you use behavior with Entry in your custom control directly?

    // inside your control 
    <Label Text="{Binding Source={x:Reference ValidationControl}, Path=Caption}"/>
    <Entry Text="{Binding Source={x:Reference ValidationControl}, Path=Value, Mode=TwoWay}">
            <Entry.Behaviors>
                <local:NumericValidationBehavior />
            </Entry.Behaviors>
    </Entry>
    

    local:NumericValidationBehavior is Behavior is for Entry , and it is reusable.

  • DimitrisMylonasDimitrisMylonas USMember ✭✭✭

    I made the custom control in order to use it in multiple cases. Different cases need different behaviors.
    As a result, I would like to add the behaviors that I want depending on the use of the custom control.
    That is the reason that we can add behaviors to a simple Entry control depending on the situation.

  • ColeXColeX Member, Xamarin Team Xamurai
    edited July 2019

    I suggest you handle the logic in custom renderer code behind.

            if (A)
            {
                entry.Behaviors.Add(new BehaviorA());
            }
            else if (B)
            {
                entry.Behaviors.Add(new BehaviorB());
            }
            else 
            {
                entry.Behaviors.Add(new BehaviorC());
            }
    
  • DimitrisMylonasDimitrisMylonas USMember ✭✭✭

    What is the if (A)?
    Don't you think that this is a very cumbersome and unpractical solution that also needs a lot of maintenance?

  • ColeXColeX Member, Xamarin Team Xamurai

    Behavior A is created and used for Control A , you can't add Behavior of Entry on your custom control .

  • IeuanWalkerIeuanWalker USMember ✭✭

    Did you ever find a solution for this?

  • DimitrisMylonasDimitrisMylonas USMember ✭✭✭

    @IeuanWalker ...not a good one… but I realized also that I made some mistakes.
    Firstly, just to describe the solution, is to create a bindable property of type bool to specify if I want to attach the behavior (or the effect)
    On property change of the bindable property I add the behavior by code.
    It’s not a pretty solution. I can re-use the behaviors or the effects which is good but I need to create a few bindable properties… which is not good.
    The default value of the bindable property is false so my XAML is not that verbose. In my case I only had 2 behaviors and 1 effect so it worked for me.
    I think that one mistake that I did is that the behaviors (or the effects) should be for the ContentView that contains the entry instead of the entry.

  • @DimitrisMylonas said:
    @IeuanWalker ...not a good one… but I realized also that I made some mistakes.
    Firstly, just to describe the solution, is to create a bindable property of type bool to specify if I want to attach the behavior (or the effect)
    On property change of the bindable property I add the behavior by code.
    It’s not a pretty solution. I can re-use the behaviors or the effects which is good but I need to create a few bindable properties… which is not good.
    The default value of the bindable property is false so my XAML is not that verbose. In my case I only had 2 behaviors and 1 effect so it worked for me.
    I think that one mistake that I did is that the behaviors (or the effects) should be for the ContentView that contains the entry instead of the entry.

    I'm was searching to the same thing. My solution was:
    1 - Create a List<Behavior> as a Bindable property inside the component
    2- Name you entry in code behind
    3- Enter the following code when creting the bindable property

     public static readonly BindableProperty EntryBehaviorsProperty = BindableProperty.Create(nameof(EntryBehaviors), typeof(List<Behavior<Entry>>), typeof(List<Behavior<Entry>>), null, BindingMode.OneTime, propertyChanged: (bindable, oldValue, value) =>
             {
                 var view = bindable as FloatingLabelInput;
                 if (view.EntryBehaviors != null && view.EntryBehaviors.Count >0)
                 {
                     foreach (var item in view.EntryBehaviors)
                     {
                         view.EntryField.Behaviors.Add(item);
                     }
    
                 }
             });
    

    4- Populate the list in the viewModel (with any behaviors you need) and binding to the component

    <customcontrolwithentryinside EntryBehaviors="{Binding EntryBehavior}">
    
    
Sign In or Register to comment.