0
votes

I am trying to create my first Xamarin.Forms custom user control named LocationSelector. It has an Entry and when the user enters something, a list with selectable locations is shown (similary to the selection in Google Maps).

The selected location is the important 'return value' of the control. My plan is to catch the ItemSelected event of the list and set the SelectedLocation property. LocationSelector is designed as MVVM and since everything is working so far here just the Code-Behind (which I think is enough to describe the problem):

public partial class LocationSelector : StackLayout
{
    public static readonly BindableProperty SelectedLocationProperty =
      BindableProperty.Create<LocationSelector, LocationModel>(s => s.SelectedLocation, new LocationModel(), BindingMode.TwoWay);

    public LocationSelector()
    {
        InitializeComponent();
        var model = new LocationSelectorModel();
        BindingContext = model;

        _listView.ItemSelected += (sender, args) =>
        {
            SelectedLocation = model.SelectedLocation;
        };
    }

    public LocationModel SelectedLocation
    {
        get { return (LocationModel)GetValue(SelectedLocationProperty); }
        set { SetValue(SelectedLocationProperty, value); }
    }
}

Now I want to use this control on a search view where the BindingContext is set to the SearchViewModel:

<ContentPage x:Class="Application.App.Views.SearchView" ...>
    <c:LocationSelector SelectedLocation="{Binding Location}"/>
</ContentPage>

public class SearchViewModel : ViewModel
{
    private LocationModel _location;
    public LocationModel Location
    {
        get { return _location; }
        set { SetProperty(ref _location, value); }
    }       
}

Unfortunately this is not working. The output throws a binding warning:

Binding: 'Location' property not found on 'Application.App.CustomControls.LocationSelectorModel', target property: 'Application.App.CustomControls.LocationSelector.SelectedLocation'

Why points the binding to a property in the ViewModel that is used 'within' my custom control and not to the property in the BindingContext of the view?

1
in your LocationSelector() constructor you are explicitly setting the BindingContext to an instance of LocationSelectorModel.Jason
This is what I afraid of. Does this mean that i cannot create user controls in MVVM style?core
Standard controls don't each have their own ViewModel. They just have a BindingContext. Your control should get it's BindingContext via a property, or inherit from it's parent.Jason
This sounds like a quite huge restriction to me. Because so I am not able to write independently working user controls. In my case for example the list with suggestions and some visible flags are just important within the user control and I don't want to care about them on every usage of the control. But maybe I didn't understand the concept of custom user controls so far. Or I need to write them complete in code rather than XAML & code (I guess this would work)?!core
If there are elements within your control that you want bound to some hardcoded (or internal) values, and others that you want bound to the external binding context of the control, you can do that, you will just need to use multiple binding contexts.Jason

1 Answers

3
votes

The problem is setting the BindingContext to the view model of the user control:

public LocationSelector()
{
    var model = new LocationSelectorModel();
    BindingContext = model; // this causes the problem
    // ...
}

In this post I found the solution. Setting the BindingContext to each child elements rather than the whole user control is doing the job:

public LocationSelector()
{
    var model = new LocationSelectorModel();
    foreach (var child in Children)
    {
        child.BindingContext = model;
    }
}