3
votes

I feel like I am missing something very obvious. I have a custom control that has a view model with a bunch of fields inside it but the important one for this example is a text value. I can bind to that very easily using the following inside the custom control XAML.

<Label Text="{Binding Text}" />

I want to expose this to anything calling this custom control. Which as far as I am aware requires the use of a bindable property

public static readonly BindableProperty TextProperty = BindableProperty.Create(propertyName: nameof(Text)
                                                               , returnType: typeof(string)
                                                               , declaringType: typeof(CustomControl));
public string Text
{
    get
    {
        return GetValue(TextProperty).ToString();
    }
    set
    {
        SetValue(TextProperty, value);
    }
}

Which works. The problem is I don't want to be binding to something in the views code behind when I already have a viewmodel for the view but can see no way of going from a bindable property to a viewmodel field.

I at first tried using the property changed event of the bindable property however this has to be static so it can not access the controls view model/binding context. I tried using the set on the Text field but these do not seem to actually get called. Neither of these worked and it seems inefficient to have a text field in the code behind purely to update a field in the view model

Edit: just to try and explain further, I have a page with a viewmodel

I have a custom control which has xaml bound to a view model

the custom control is used on the page likes so

<ctrl:CustomControl Text="{Binding ControlText}"/>

Currently that will set the Text dependency property and backing field in the custom controls code behind correctly to whatever the Pages viewmodel ControlText is.

Instead I want this to set the Text field on the Custom controls viewmodel and fire the viewmodels property changed event.

so basically it will go PageVM.ControlText --> CustomControlVM.Text

1
It is not clear how many entities are involved in your problem. So you have a custom control (only cs no additional xaml I took from your description). Now you have another xaml view plus a corresponding viewmodel and in that view you want to use your custom control and bind one of its bindable properties to a property in the viewmodel?Mouse On Mars
I'm not 100% sure I understand your question, but I think that what you may be looking for is TwoWay data binding (docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/…). Change your xaml to: <Label Text="{Binding Text, Mode=TwoWay}" />akseli
Sorry if I have explained this poorly, I have added an edit that will hopefully make it clearer what I am trying to achievewolfman1001

1 Answers

0
votes

I make a custom control with bindable property. If you want to perform an action on a BindableProperty change, you need to attach to one of its property change events. You miss the PropertyChanged event in your code.

MyCustomControl:

<StackLayout>
        <Label x:Name="Title" BackgroundColor="Red" TextColor="White" HeightRequest="60" Text="A"/>
        <Label BackgroundColor="Green" TextColor="Black" HeightRequest="60" Text="B"></Label>
    </StackLayout>

BindableProperty:

private string _text;
    public string Text
    {
        get { return _text; }
        set
        {
            _text = value;
            OnPropertyChanged();
        }
    }
    public static readonly BindableProperty TextProperty = BindableProperty.Create(
             nameof(Text),
             typeof(string),
             typeof(MyCustomControl),
             string.Empty,
             propertyChanged: (bindable, oldValue, newValue) =>
             {
                 var control = bindable as MyCustomControl;
                 //var changingFrom = oldValue as string;
                 //var changingTo = newValue as string;
                 control.Title.Text = newValue.ToString(); //Title is the name of the label which I want to change the Text.
             });

ViewModel:

public class ViewModel
{
    public string Text { get; set; }
}

My use of custom control: Please do not forget to add the reference of local.

<local1:MyCustomControl Text="{Binding Text}"></local1:MyCustomControl>

Binding:

ViewModel viewModel = new ViewModel();
        viewModel.Text = "hello, ";
        this.BindingContext = viewModel;

Result: enter image description here

You could download the source file from the MyCustomControl folder on GitHUb for reference. https://github.com/WendyZang/Test.git