-1

I'm struggeling a bit with a bindable property and the propertyChanged event not firing when new text is entered.

I've made a minimal codesample:

Xaml custom control:

<Grid  xmlns="http://xamarin.com/schemas/2014/forms" 
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="BindingPropertyProject.CustomFlyout">
<Entry x:Name="MyEntry"/>

Codebehind:

   public partial class CustomFlyout : Grid
{
    public CustomFlyout()
    {
        InitializeComponent();
    }

    public string MyEntryText
    {
        get { return (string)GetValue(MyEntryTextProperty); }
        set
        {
            SetValue(MyEntryTextProperty, value);
        }
    }

    public static readonly BindableProperty MyEntryTextProperty =
        BindableProperty.Create(nameof(MyEntryText), typeof(string),
            typeof(CustomFlyout),
            defaultValue: string.Empty,
            defaultBindingMode: BindingMode.TwoWay
            , propertyChanging: TextChanged);

    private static void TextChanged(BindableObject bindable, object oldValue, object newValue)
    {

        if (bindable is CustomFlyout control)
        {
            control.MyEntry.Text = newValue?.ToString();
        }
    }
}

}

Consuming class xaml:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:BindingPropertyProject"
         x:Class="BindingPropertyProject.MainPage">

<Grid>
    <local:CustomFlyout MyEntryText="{Binding TextPropertyFromBindingContext, Mode=TwoWay}" HorizontalOptions="FillAndExpand" VerticalOptions="Start"/>
</Grid>

Consuming class codebehind:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        BindingContext = this;
    }


    private string _textPropertyFromBindingContext = "bound";
    public string TextPropertyFromBindingContext
    {
        get 
        {
            return _textPropertyFromBindingContext; 
        }
        set
        {
            if (_textPropertyFromBindingContext != value)
            {
                _textPropertyFromBindingContext = value;
                OnPropertyChanged();
            }
        }
    }

}

It binds the "bound" value just fine, but subsequent changes entered in the entry does not raise property changed.

I've tried a number of suggestions i found from googeling, but this should be fine right?

UPDATE: Ok - so i actually got i to work by adding binding in the custom view:

<Grid  xmlns="http://xamarin.com/schemas/2014/forms" 
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="BindingPropertyProject.CustomFlyout">

<Entry x:Name="MyEntry" Text="{Binding TextPropertyFromBindingContext }"/>

Is this really the way to do it? I mean - i could only make it work, if bindings was named EXACTLY the same in custom view, and consuming part..

Cheesebaron
  • 24,131
  • 15
  • 66
  • 118
OneBigQuestion
  • 149
  • 6
  • 19
  • I have updated answer with Entry control to match your question. Earlier I have used Label. Please check. – Ranjit Mar 22 '21 at 14:53

2 Answers2

1

i could only make it work, if bindings was named EXACTLY the same in custom view, and consuming part..

It's not necessary to have same binding name. Please refer following code.

Custom Control

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="StackQA2XF.CustomControl.MyCustomControl">
    <ContentView.Content>
        <Entry x:Name="CustomEntry"/>
    </ContentView.Content>
</ContentView>

  public partial class MyCustomControl : ContentView
    {
        public static readonly BindableProperty EntryTextProperty =
            BindableProperty.Create(nameof(EntryText), typeof(string), typeof(MyCustomControl), default(string), BindingMode.TwoWay);

        public string EntryText
        {
            get { return (string)GetValue(EntryTextProperty); }
            set { SetValue(EntryTextProperty, value); }
        }

        public MyCustomControl()
        {
            InitializeComponent();
            CustomEntry.SetBinding(Entry.TextProperty, new Binding(nameof(EntryText), source: this));
        }
    }

Consuming Class

 <customcontrols:MyCustomControl EntryText="{Binding TitleText}"/>

 public class MainViewModel : INotifyPropertyChanged
    {
        private string _titleText = "Good morning";
        public string TitleText
        {
            get
            {
                return _titleText;
            }
            set
            {
                _titleText = value;
                OnPropertyChange(nameof(TitleText));
            }
        }
       
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChange(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }
    }

Please do binding in the code for custom control and raise property change for the binding property in viewmodel.

CustomEntry.SetBinding(Entry.TextProperty, new Binding(nameof(EntryText), source: this));

OnPropertyChange(nameof(TitleText));

Please refer https://www.youtube.com/watch?v=ZViJyL9Ptqg.

I have tested this code able to get fired propertyChanged event when Entry text is changed from custom view.

Ranjit
  • 833
  • 8
  • 15
0

It binds the "bound" value just fine, but subsequent changes entered in the entry does not raise property changed.

From Bindable Properties property changes, BindableProperty MyEntryTextProperty binding TextPropertyFromBindingContext, so the propertyChanged event will be fired when you change TextPropertyFromBindingContext, Instead of changing the value of MyEntry.

You can change TextPropertyFromBindingContext bu Button.click, then you will see the propertyChanged event will be fired.

public partial class Page3 : ContentPage, INotifyPropertyChanged
{

    private string _textPropertyFromBindingContext = "bound";
    public string TextPropertyFromBindingContext
    {
        get
        {
            return _textPropertyFromBindingContext;
        }
        set
        {
            if (_textPropertyFromBindingContext != value)
            {
                _textPropertyFromBindingContext = value;
                RaisePropertyChanged("TextPropertyFromBindingContext");
            }
        }
    }
    public Page3()
    {
        InitializeComponent();
        this.BindingContext = this;
       
    }

  
    public event PropertyChangedEventHandler PropertyChanged;    
    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    private void btn1_Clicked(object sender, EventArgs e)
    {
        TextPropertyFromBindingContext = "test";
    }
}
Cherry Bu - MSFT
  • 10,160
  • 1
  • 10
  • 16