4

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);
}
tagtraeumer
  • 1,451
  • 11
  • 19
  • To explain what is going on, show more xaml/code. Sounds like confusion between **page**'s BindingContext, and **component's** BindingContext. Please show a **complete (but minimal) example** of the problem. A simple page that includes the component. The page's code behind - does the page have a BindingContext? A ViewModel? Then a simplified version of the CustomComponent, both xaml and code. But you have stumbled upon the key fact: Its easier to work with a CustomComponent if it is self-contained, does not refer to a separate viewmodel. (The page can still have a VM.) – ToolmakerSteve May 22 '22 at 23:33
  • hey thanks for your comment. but no, I really mean the BindingContext of the CustomComponent. The page itself has a ViewModel, which is used to pass the information to the component (as seen in my example). I will try to come up with a minimal example. cheers – tagtraeumer May 23 '22 at 08:51
  • @ToolmakerSteve I created a new default project (Tabbed App) on VS and created two example components, one using a BindingContext, the other one without. The code is on GitHub: https://github.com/tagtraeumer/xamarin-issue-customcomponent-binding these components are used in the browse page. As u can see the component without ViewModel shows the item name, the component with a ViewModel is blank on this position. A random number is displayed there which originates from the VM – tagtraeumer May 23 '22 at 15:18
  • I understand. I've added to my answer. – ToolmakerSteve May 23 '22 at 22:39

1 Answers1

3

"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}}" />
ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • thanks, I guess I can work with the last solution. I tested it with the VM and changing the value and everything worked as expected. – tagtraeumer May 24 '22 at 08:44
  • Is there a way to use viewmodel with ObservableObject from community toolkit? So we can leverage all the code gen and [RelayCommand], etc? – Adam B Jan 14 '23 at 03:56
  • Yes, `public class MyViewModel : ObservableObject` works fine. Just be sure to write xaml similar to code snippet at end of answer. – ToolmakerSteve Jan 14 '23 at 04:32