In Xamarin.Forms, how to allow for autocompletion for bindings in XAML code in the case you can't instantiate the BindingContext from XAML?

Viewed 486

Given the following project:

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="A.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:A">
    <ContentPage.Content>
        <StackLayout>
            <StackLayout>
                <Button Clicked="Greet" Text="Greet" />
            </StackLayout>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

MainPage.xaml.cs

using System;
using Xamarin.Forms;

namespace A
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void Greet(object sender, EventArgs e)
        {
            Navigation.PushModalAsync(new SubPage
            {
                BindingContext = new SubPageViewModel("World")
            });
        }
    }
}

SubPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="A.SubPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
    <ContentPage.Content>
        <StackLayout>
            <Label
                HorizontalOptions="CenterAndExpand"
                Text="{Binding Greeting}"
                VerticalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

SubPage.xaml.cs

using Xamarin.Forms;

namespace A
{
    public partial class SubPage : ContentPage
    {
        public SubPage ()
        {
            InitializeComponent ();
        }
    }
}

SubPageViewModel.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace A
{
    public class SubPageViewModel : INotifyPropertyChanged
    {
        private string place;

        public string Place
        {
            get => place;
            set
            {
                if(place != value)
                    return;
                place = value;
                OnPropertyChanged();
                OnPropertyChanged(nameof(Greeting));
            }
        }

        public SubPageViewModel(string place)
        {
            this.place = place;
        }

        public string Greeting => $"Hello, {place}";

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Visual Studio won't autocomplete bindings in SubPage.xaml and will be complaining that it "Cannot resolve symbol 'Greeting' due to unknown DataContext", because the syntax highlighter doesn't know the type at the compile time. Typically, I'd use the following syntax:

<ContentPage.BindingContext>
    <a:SubPageViewModel />
</ContentPage.BindingContext>

however, this isn't applicable here, since the ViewModel is not default constructible.

If this was WPF, I'd be using mc:Ignorable="d" together with d:DesignInstance, however, DesignInstance doesn't seem to be implemented in XF.

How do I make autocompletion work?

2 Answers

You can declare a dummy static property which will be used in a binding.

SubPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="A.SubPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:a="clr-namespace:A;assembly=A.Android"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    BindingContext="{x:Static a:SubPage.BindingContextDummyInstance}"> <!-- <------ added -->
    <ContentPage.Content>
        <StackLayout>
            <Label
                HorizontalOptions="CenterAndExpand"
                Text="{Binding Greeting}"
                VerticalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

SubPage.xaml.cs

using Xamarin.Forms;

namespace A
{
    public partial class SubPage : ContentPage
    {
        public static SubPageViewModel BindingContextDummyInstance => null; // <------ added

        public SubPage ()
        {
            InitializeComponent ();
        }
    }
}

This changes nothing with regards to code semantics since the default BindingContext is still null, but now autocompletion is working, because the BindingContext is known at compile time.

You can try:

<ContentPage.BindingContext>
    <x:Type Type="a:SubPageViewModel " />
</ContentPage.BindingContext>
Related