在Xamarin.Forms中,如果无法从XAML实例化BindingContext,如何在XAML代码中允许自动完成绑定?

时间:2017-11-14 21:55:44

标签: c# xaml mvvm xamarin.forms

鉴于以下项目:

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不会在SubPage.xaml中自动完成绑定,并且会抱怨它“由于未知的DataContext而无法解析符号'问候',因为语法突出显示器在编译时不知道类型。通常,我使用以下语法:

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

但是,这不适用于此,因为ViewModel不是默认可构造的。

如果这是WPF,我会mc:Ignorable="d"d:DesignInstance一起使用,但是DesignInstance似乎没有在XF中实现。

如何使自动完成工作?

2 个答案:

答案 0 :(得分:2)

您可以声明将在绑定中使用的虚拟静态属性。

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 ();
        }
    }
}

这对代码语义没有任何改变,因为默认的BindingContext仍然是null,但现在自动完成正在工作,因为BindingContext在编译时是已知的。

答案 1 :(得分:0)

您可以尝试:

<script>
$(document).ready(function() {
  var review_text = $("#review_text");
  var counter     = $("#counter");
  var max_length  = counter.data("maximum-length");

  counter.text(max_length - review_text.val().length);
  review_text.keyup(function() {
      counter.text(max_length - $(this).val().length);
  });

});
</script>