Search code examples
c#xamarin.formsbindableproperty

Xamarin BindableProperty works with binding only when I don't use BindingContext


in Xamarin Forms I created a Page that contains a custom component which I want to feed a value just like this:

<c:CustomComponent Test="{Binding Test}" />

This, however, doesn't work. When I use a raw number instead of the Binding it works. The problem that I figured out was, that my custom component used a ViewModel / BindingContext. So when I remove the line where I assign my ViewModel to the BindingContext the Binding works.

why is that so and how can I use use both, the BindingContext as well as BindableProperty within my custom component? Or do I have to do everything within my code behind?

For reference some code example how I created the BindableProperty

public static readonly BindableProperty TestProperty = BindableProperty.Create(nameof(Test), typeof(int),
    typeof(CustomComponent), propertyChanged: (bindable, oldVal, newVal) => {
        Debug.WriteLine("TEST " + newVal);
    });

public int Test {
    get => (int)GetValue(TestProperty);
    set => SetValue(TestProperty, value);
}

Solution

  • "my custom component used a ViewModel / BindingContext."

    Its easier to create a reusable custom component, if it is "self-contained" - no BindingContext.

    Constructor:

    public CustomComponent()
    {
        InitializeComponent();
    }
    

    Move EVERYTHING you currently have in the component's viewmodel, into the xaml.cs code behind file.

    Now in CustomComponent.xaml, give it a name (here theComponent):

    <ContentView ...
     x:Name="theComponent"
     x:Class=...>
    

    This comes in handy when component's xaml wants to bind to a property in itself:

    <Label Text="{Binding TestString, Source={x:Reference theComponent}}" />
    
    public string TestString
    {
        get => _testString;
        set {
            _testString = value;
            OnPropertyChanged();
        }
    }
    private string _testString = "test";
    

    tl;dr: If component has an x:Name="theComponent" in its xaml, can use {Binding ..., Source={x:Reference theComponent}}, to refer to its own properties. No BindingContext needed.


    If you want the component to have an associated ViewModel, with the above technique you don't have to set BindingContext to that VM. Do it like this:

    public class MyViewModel
    {
        public string TestString
        {
            get => _testString;
            set {
                _testString = value;
                OnPropertyChanged();
            }
        }
        private string _testString = "test";
    }
    

    CustomComponent:

    public MyViewModel VM { get; private set; }
    public CustomComponent()
    {
        InitializeComponent();
        VM = new MyViewModel();
    }
    

    Usage in xaml:

    <Label Text="{Binding VM.TestString, Source={x:Reference theComponent}}" />