John Livermore
John Livermore

Reputation: 31343

Xamarin Forms binding - intercepting a bound value and changing it

I have a simple composed custom control that displays text set to a bound ControlText property. In the example below, you can see when the button is clicked the control is updated.

enter image description here

How can I change the code so that the label shown by the control takes whatever is sent to it and converts it to all uppercase?

So instead of showing...

Count=5

it would show...

COUNT=5

In this simple example an IValueConverter can be leveraged to accomplish this, but I want to see a different implementation for a much more complex example I need to implement. I am seeking a solution that intercepts the value being set in the code behind, converts it, and sets it to the ControlText property of the custom control.

SimpleControl.xaml.cs

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SimpleControl : ContentView
{
    public SimpleControl ()
    {
        InitializeComponent ();
    }

    public static readonly BindableProperty ControlTextProperty = BindableProperty.Create(
                                           propertyName: nameof(ControlText),
                                           returnType: typeof(string),
                                           declaringType: typeof(SimpleControl),
                                           defaultBindingMode: BindingMode.TwoWay,
                                           defaultValue: "Hello World");

    public string ControlText
    {
        get { return (string)base.GetValue(ControlTextProperty); }
        set { base.SetValue(ControlTextProperty, value); }
    }
}

Also, I would expect at runtime this breakpoint to be hit, but the code never stops on it. I am setting the property from the SimplePageModel, so I find it strange this is never hit. Can someone explain that to me as well?

enter image description here

SimpleControl.xaml

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App7.SimpleControl"
             x:Name="this">
    <ContentView.Content>
        <StackLayout Margin="100">
            <Label Text="{Binding Source={x:Reference this}, Path=ControlText}" />
        </StackLayout>
    </ContentView.Content>
</ContentView>

SimplePage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:App7"
             x:Class="App7.SimplePage">
    <ContentPage.Content>
        <StackLayout>
            <local:SimpleControl ControlText="{Binding ControlText}" />

            <Button Text="Update Control"
                Command="{Binding UpdateControl}" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

SimplePageModel.cs (leveraging FreshMVVM)

public class SimplePageModel : FreshBasePageModel
{
    public SimplePageModel() { }

    private int _index;

    public string ControlText { get; set; }

    public Command UpdateControl
    {
        get
        {
            return new Command((t) =>
            {
                ControlText = $"Count = {++_index}";
            });
        }
    }

    public override void Init(object initData)
    {
        ControlText = $"Count = 0";

        base.Init(initData);
    }
}

Upvotes: 3

Views: 335

Answers (2)

Nick Kovalsky
Nick Kovalsky

Reputation: 6502

Direct answer to the question : change the definition of your property from

 public static readonly BindableProperty ControlTextProperty = BindableProperty.Create(
                                           propertyName: nameof(ControlText),
                                           returnType: typeof(string),
                                           declaringType: typeof(SimpleControl),
                                           defaultBindingMode: BindingMode.TwoWay,
                                           defaultValue: "Hello World");

to

 public static readonly BindableProperty ControlTextProperty = BindableProperty.Create(
                                           propertyName: nameof(ControlText),
                                           returnType: typeof(string),
                                           declaringType: typeof(SimpleControl),
                                           defaultBindingMode: BindingMode.TwoWay,
                                           defaultValue: "Hello World", 
coerceValue: (bindable, value) =>
            {
                if (value!=null)
                    return ((string) value).ToUpper();
                return value;
            });

Upvotes: 0

zpouip
zpouip

Reputation: 787

You can also use triggers for this purpose, since its not too clear what is the idea in the background, I am just suggesting that it can be helpful: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/triggers

Upvotes: 0

Related Questions