忽略Binding初始化

Emi*_*m23 5 xaml binding initialization xamarin xamarin.forms

初始问题来自关于Xamarin.Forms.Map的折线的个人项目,其中初始化是通过XAML部件的绑定实现的.

让我通过一个例子来说明一点:

我有一个 继承自的CustomMap.cs对象Xamarin.Forms.Map (此文件位于PCL部分 - > CustomControl/CustomMap.cs)

public class CustomMap : Map, INotifyPropertyChanged
{
    public static readonly BindableProperty PolylineAddressPointsProperty =
        BindableProperty.Create(nameof(PolylineAddressPoints), typeof(List<string>), typeof(CustomMap), null);
    public List<string> PolylineAddressPoints
    {
        get { return (List<string>)GetValue(PolylineAddressPointsProperty); }
        set
        {
            SetValue(PolylineAddressPointsProperty, value);
            this.GeneratePolylineCoordinatesInner();
        }
    }   
    // ...
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我有一个可评估的可绑定属性,而XAML似乎没有使用此评估器.

因此,调用控件的页面的MainPge.xaml部分如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:control="clr-namespace:MapPolylineProject.CustomControl;assembly=MapPolylineProject"
         x:Class="MapPolylineProject.Page.MainPage">

  <ContentPage.Content>
    <control:CustomMap x:Name="MapTest" PolylineAddressPoints="{Binding AddressPointList}"
                                       VerticalOptions="Fill" HorizontalOptions="Fill"/>

  </ContentPage.Content>

</ContentPage>
Run Code Online (Sandbox Code Playgroud)

MainPge.xaml.cs部分:

public partial class MainPage : ContentPage
{
    public List<string> AddressPointList { get; set; }

    public MainPage()
    {
        base.BindingContext = this;

        AddressPointList = new List<string>()
        {
            "72230 Ruaudin, France",
            "72100 Le Mans, France",
            "77500 Chelles, France"
        };

        InitializeComponent();

        //MapTest.PolylineAddressPoints = AddressPointList;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以,如果我PolylineAddressPoints从对象实例编辑它(如果注释的部分没有被'评论过),一切都很好,但是如果我从XAML(来自InitializeComponent();)初始化值,它就不起作用了SetValue,在Set {},的CustomMap.PolylineAddressPoints,不叫...

然后我在网上搜索了它并得到了一些关于依赖属性的东西或类似的东西.所以我尝试了一些解决方案,但是,从WPF,所以一些方法,如DependencyProperty.Register();.所以是的,我找不到解决问题的方法..

我也DependencyProperty.Register();想知道一些事情,如果存在于Xamarin.Forms中,那么这意味着我必须为每个值做这件事吗?因为,如果每个值都必须由XAML绑定逻辑设置,它就行不通,我必须注册每个值,不是吗?

对不起,如果我不清楚,但我很失落关于这个问题..请不要犹豫,要求更多的细节,预先感谢!

最后,最初的问题是我试图从XAML设置一个对象/控件的值.通过绑定执行此操作不起作用,它似乎被忽略..但是,如果我执行以下操作它确实有效:

MapTest.PolylineAddressPoints = AddressPointList;  
Run Code Online (Sandbox Code Playgroud)

Ste*_*oix 7

这里面有多个问题:

  • 为什么在使用 Xaml 时从未调用属性设置器?
  • 我是否正确定义了我的 BindableProperty ?
  • 为什么我的绑定失败?

让我以不同的顺序回答它们。

我是否正确定义了我的 BindableProperty ?

BindableProperty 声明是正确的,但可以通过使用一个来改进IList<string>

public static readonly BindableProperty PolylineAddressPointsProperty =
    BindableProperty.Create(nameof(PolylineAddressPoints), typeof(IList<string>), typeof(CustomMap), null);
Run Code Online (Sandbox Code Playgroud)

但是属性访问器是错误的,应该只包含这个:

public IList<string> PolylineAddressPoints
{
    get { return (IList<string>)GetValue(PolylineAddressPointsProperty); }
    set { SetValue(PolylineAddressPointsProperty, value); }
}
Run Code Online (Sandbox Code Playgroud)

我会在回答下一个问题时告诉你为什么。但是你想在属性改变时调用一个方法。为此,您必须将propertyChanged委托引用到CreateBindableProperty,如下所示:

public static readonly BindableProperty PolylineAddressPointsProperty =
    BindableProperty.Create(nameof(PolylineAddressPoints), typeof(IList<string>), typeof(CustomMap), null,
                            propertyChanged: OnPolyLineAddressPointsPropertyChanged);
Run Code Online (Sandbox Code Playgroud)

你也必须声明这个方法:

static void OnPolyLineAddressPointsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
    ((CustomMap)bindable).OnPolyLineAddressPointsPropertyChanged((IList<string>)oldValue, (IList<string>)newValue);
}

void OnPolyLineAddressPointsPropertyChanged(IList<string> oldValue, IList<string> newValue)
{
    GeneratePolylineCoordinatesInner();
}
Run Code Online (Sandbox Code Playgroud)

为什么在使用 Xaml 时从未调用属性设置器?

属性和属性访问器仅在通过代码访问属性时才被调用。C#代码。

使用来自 Xaml 的 BindablePrperty 后备存储设置属性时,将绕过属性访问器并SetValue()直接使用。

Binding从代码或 Xaml定义 a 时,属性访问器将再次被绕过,并SetValue()在需要修改属性时使用。并且当SetValue()被调用时,propertyChanged委托在属性改变后执行(这里要完成,在属性改变之前propertyChanging调用)。

您可能想知道,如果可绑定属性仅由 xaml 使用或在 Binding 的上下文中使用,为什么还要定义该属性。好吧,我说属性访问器没有被调用,但它们在 Xaml 和 XamlC 的上下文中使用:

  • 一个[TypeConverter]属性可以在属性来定义,并且将用于
  • XamlC上,物业签名可以被用来推断,在编译时,该TypeBindableProperty

因此,始终为公共 BindableProperties 声明属性访问器是一个好习惯。总是。

为什么我的绑定失败?

当您CustomMap同时使用ViewViewModel(我不会告诉 Mvvm Police)时,在您的构造函数中执行此操作就足够了:

BindingContext = this; //no need to prefix it with base.
Run Code Online (Sandbox Code Playgroud)

正如您已经在做的那样,Binding一旦您BindableProperty按照我之前解释的方式修改了声明,您就应该可以工作。