eventsxamarin.formsbindableproperty

Pass-through TextChanged Bindableproperty from a custom Entry control to the actual Entry


I have a custom control, which is basically a XML wrapper around another custom control, with its own CustomRenderer.

Custom Control, basically a Wrapper XAML for another custom control

<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="Test.Controls.TitleAndEntry"
    xmlns:renderers="clr-namespace:Test.Renderers">
    <StackLayout>
        <Label
            FontAttributes="Bold"
            Style="{StaticResource TitleSemiBoldBlackLabel}"/>
        <renderers:EntryBottomLine
            x:Name="myEntry"
            PlaceholderColor="{StaticResource PrimarySolidGrayColor}"
            IsPassword="False"
            TextColor="{StaticResource BlackColor}"/>        
    </StackLayout>
</ContentView>

Custom Control Wrapper Code-Behind

public partial class TitleAndEntry : ContentView
    {
        public TitleAndEntry()
        {
            InitializeComponent();
        }

        // Other BindableProperties & code

        public static BindableProperty TextEntryChangedProperty = BindableProperty.Create(
            nameof(TextEntryChanged), typeof(EventHandler<TextChangedEventArgs>), typeof(TitleAndEntry), null,
            propertyChanged: OnTextEntryChanged);

        public EventHandler<TextChangedEventArgs> TextEntryChanged
        {
            get
            {
                return (EventHandler<TextChangedEventArgs>)GetValue(TextEntryChangedProperty);
            }
            set
            {
                SetValue(TextEntryChangedProperty, value);
            }
        }

        private static void OnTextEntryChanged(BindableObject bindable, object oldVal, object newVal)
        {
            var titleAndEntry = (TitleAndEntry)bindable;
            titleAndEntry.myEntry.TextChanged += (EventHandler<TextChangedEventArgs>)newVal;
        }

    }
}

XAML on the page where I use the custom control

 <ctrl:TitleAndEntry
    x:Name="user"
    Margin="{StaticResource NormalTopPadding}"
    TextLabel="{x:Static local:AppResources.User}"
    TextChanged="OnMyTextChanged"/>

Code-behind of that page

 private void OnMyTextChanged(object sender, TextChangedEventArgs e)
{
    // Call to Viewmodel
}

I get this error:

Xamarin Forms No property, bindable property, or event found for 'TextChanged', or mismatching type between value and property

I tried many suggestions, but I cannot get it to work.


Solution

  • I'll answer it myself:

    After going back to the InputView (which is the base class for Entry), I noticed that TextChanged is not a BindableProperty, but an event.

    public event EventHandler<TextChangedEventArgs> TextChanged;
    

    So I removed the entire BindableProperty and replaced it with:

    // On the regular Text propert, call the event handler from the PropertyChanged param
    public static readonly BindableProperty TextProperty =
        BindableProperty.Create(
            nameof(Text),
            typeof(string),
            typeof(TitleAndEntry),
            null,
            BindingMode.TwoWay,
            propertyChanged: (bindable, oldValue, newValue) => ((TitleAndEntry)bindable).OnTextChanged((TitleAndEntry)bindable, (string)oldValue, (string)newValue));
    
    public event EventHandler<TextChangedEventArgs> TextChanged;
    
    // Simply Invoke the event with the provided args
    private void OnTextChanged(TitleAndEntry bindable, string oldValue, string newValue)
    {
        this.TextChanged?.Invoke(bindable, new TextChangedEventArgs(oldValue, newValue));
    }
    

    Now it works as it should.