忽略Binding初始化

时间:2016-09-14 13:38:13

标签: xaml xamarin binding initialization xamarin.forms

初始问题来自personal project about the polyline of the Xamarin.Forms.Map,初始化是通过XAML部分的绑定实现的。

让我通过一个例子说清楚:

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

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

正如您所看到的,我与评估员有一个可绑定的属性,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>

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

所以,如果我从对象实例编辑PolylineAddressPoints(如果注释部分不是&#39;评论...),那么一切都很好,但是如果我从XAML(来自InitializeComponent();),它不起作用,SetValueSet {}的{​​{1}}未被调用。

然后我在网上搜索了它并获得了一些关于依赖属性?或类似的东西。所以我尝试了一些解决方案,但是从WPF开始,有些方法,比如CustomMap.PolylineAddressPoints。所以,是的,我无法找到解决问题的方法..

我还有一些事情,如果 Xamarin.Forms 中存在DependencyProperty.Register();,那么这意味着我必须为每个值执行此操作吗?因为,如果每个值都必须由 XAML绑定逻辑设置,那么它将不起作用,我必须注册每个值,不是吗?

对不起,如果我不清楚,但我对这个问题感到很遗憾..请不要犹豫,要求提供更多细节,谢谢!

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

DependencyProperty.Register();

1 个答案:

答案 0 :(得分:4)

这里有很多问题:

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

让我以不同的顺序回答。

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

BindableProperty声明是正确的,但可以使用IList<string>进行改进:

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

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

public IList<string> PolylineAddressPoints
{
    get { return (IList<string>)GetValue(PolylineAddressPointsProperty); }
    set { SetValue(PolylineAddressPointsProperty, value); }
}

我会在回答下一个问题时告诉你原因。但是,您希望在属性更改时调用方法。为此,您必须将propertyChanged代理人引用至CreateBindableProperty,如下所示:

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

你必须声明这个方法:

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

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

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

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

从代码或Xaml定义Binding时,会再次绕过属性访问器,并在需要修改属性时使用SetValue()。当调用SetValue()时,propertyChanged委托在属性更改后执行(要在此处完成,在属性更改之前调用})。

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

  • 可以在属性上定义propertyChanging属性,并将使用
  • 启用[TypeConverter]时,属性签名可用于在编译时推断XamlC的{​​{1}}。

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

为什么绑定失败?

当你使用Type作为BindablePropertyCustomMap时(我不会告诉Mvvm警察),在你的构造函数中执行此操作应该足够了:

View

正如您已经这样做的那样,一旦您按照我之前解释的方式修改了ViewModel声明,您的BindingContext = this; //no need to prefix it with base. 就可以正常工作。