1

I use Reflection to set the Label.TextProperty.CoerceValue to my custom delegate (TextProperty.CoerceValue are null by default) but when Label text changed, the delegate are not called

the same strategy are apply/tried on Image.SourceProperty, Entry.TextProperty all are called successful

is bug or Label.TextProperty by design will not call CoerceValue delegate?

thank you very much.

Xamarin.Forms 4.3.0.947036

var property = Label.TextProperty;
var coerceValue = property.GetType().GetProperty("CoerceValue", BindingFlags.NonPublic | BindingFlags.Instance);
oldDelegate = coerceValue?.GetValue(property) as BindableProperty.CoerceValueDelegate;
coerceValue?.SetValue(property, (bindable, value) => {
    var modified = ModifyValue(value); // simply modify the value if required
    return modified
});
codetale
  • 87
  • 6

2 Answers2

1

If you want to call CoerceValue when Label.Text changed, I suggest you can use Bindable Properties to bind Label.TextPrperty.

public partial class Page9 : ContentPage
{
    public static readonly BindableProperty labelvalueProperty = BindableProperty.Create("labelvalue", typeof(string), typeof(Page9), null , coerceValue: CoerceValue);
    public string labelvalue
    {
        get { return (string)GetValue(labelvalueProperty); }
        set { SetValue(labelvalueProperty, value); }
    }

    private static object CoerceValue(BindableObject bindable, object value)
    {
        string str = (string)value;
        if(str=="cherry")
        {
            str = "hello world!";
        }
        return str;
    }

    public Page9 ()
    {         
        InitializeComponent ();
        label1.SetBinding(Label.TextProperty, "labelvalue");

        labelvalue = "this is test";
        BindingContext = this;
    }

    private void Btn1_Clicked(object sender, EventArgs e)
    {
        labelvalue = "cherry";
    }
}

You can see the CoerceValue can be fired when Label.Text property changed.

Cherry Bu - MSFT
  • 10,160
  • 1
  • 10
  • 16
  • hi @cherry thanks for the idea, but with this solution, i have to create thousands BindableProperty for all my labels – codetale Nov 11 '19 at 23:06
  • @codetale, For label, it don't have TextChanged event, so you don't have any event to handle somethong when text changed, like entry. If you don't want to create bindableproperty, I suggest you can use bind like this:https://stackoverflow.com/questions/43595801/handle-event-when-label-text-change, I am not sure it is bug or others, so you can create one thread at github for better help. – Cherry Bu - MSFT Nov 12 '19 at 09:25
  • actually i'm not try to track the text changed event, i try to validate and change the value when text is about to update, thats why the `CoerceValue` are handy – codetale Nov 12 '19 at 12:22
  • @codetale, Now, have you solved your issue now? If yes, please share your solution here and mark it as answer, thanks. – Cherry Bu - MSFT Dec 13 '19 at 06:55
0

I created a new Page Page1 in a Xamarin.Forms Project, with the following simple code in the code behind:

public Page1()
{
    InitializeComponent();
}

protected override void OnAppearing()
{

    Label l = new Label();

    BindableProperty.CoerceValueDelegate d = (s, a) => 
    {
        string modified = "textY"; // simply modify the value if required
        return modified;
    };
    var property = Label.TextProperty;
    var coerceValue = property.GetType().GetProperty("CoerceValue", BindingFlags.NonPublic | BindingFlags.Instance);
    var oldDelegate = coerceValue?.GetValue(property) as BindableProperty.CoerceValueDelegate;
    coerceValue?.SetValue(property, d);


    l.Text = "1"; // Text property is set to textY thanks to CoerceValueDelegate!


    base.OnAppearing();
}

when i call l.Text = "1" the BindableProperty.CoerceValueDelegate i defined is correctly called, and l.Text is set to textY as expected.

@codetale, are you able to run this code on your side?

deczaloth
  • 7,094
  • 4
  • 24
  • 59
  • Hi @Julipan, weird, I found that if defined: * at `App.OnStart`, it wouldnt work * at first page `OnAppearing` its working * at `App.OnStart` wrap with BeginInvokeOnMainThread, its working – codetale Nov 10 '19 at 01:42
  • @codetale, i just copy-pasted the SetValue code in my Answer to App.OnStart, and it is correctly working. After i set the value of my label, the CoerceValueDelegate is called. I am using X.F. 4.3. If you use the code as in my Answer in the App.OnStart (without BeginInvokeOnMainThread), is the CoerceValueDelegate not being called? – deczaloth Nov 10 '19 at 21:08
  • yes i am using your code in App.OnStart, but have to wrap ```coerceValue?.SetValue(property, d);``` in BeginInvokeOnMainThread to have the delegate get called. no idea why... – codetale Nov 11 '19 at 23:03
  • 1
    hi @Julipan, i found that if you remove ```Label l = new Label();l.Text = "1";``` from your code but put in on XAML and set `MainPage` to this XAML after the delegate are set. Then the `CoerceValueDelegate` will not called unless wrap ```coerceValue?.SetValue(property, d);``` in BeginInvokeOnMainThread – codetale Nov 12 '19 at 12:30