忽略绑定初始化 [英] Ignore the Binding initialization

查看:85
本文介绍了忽略绑定初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最初的问题来自于关于 Xamarin.Forms.Map 的折线,其中通过XAML部分的绑定来实现初始化.

The inital problem is coming from a personal project about the polyline of the Xamarin.Forms.Map where the initialization is realized by a binding from the XAML part..

让我通过一个例子来弄清楚:

Let me be clear by an example :

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

I have an object CustomMap.cs which inherit from Xamarin.Forms.Map (This file is in the PCL part -> 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();
        }
    }   
    // ...
}

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

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

So the MainPge.xaml part of the page, where the control is called, looks like that:

<?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(如果未注释的部分未注释),则一切正常,但是如果我从XAML(从InitializeComponent();),它不起作用,没有调用CustomMap.PolylineAddressPointsSet {}中的SetValue.

So, everything is fine if I edit the PolylineAddressPoints from the object instance (if the commented part isnt' commented..), but if I init the value from the XAML (from the InitializeComponent();), it doesn't work, the SetValue, in the Set {}, of the CustomMap.PolylineAddressPoints, isn't called..

然后,我在网上搜索了有关此内容,并获得了有关依赖项属性?的信息.因此,我尝试了一些解决方案,但是从WPF开始,尝试了一些方法,例如DependencyProperty.Register();.是的,我找不到解决问题的方法.

I then searched on the web about it and get something about the Dependency Properties? or something like that. So I tried some solutions but, from WPF, so some methods, such as DependencyProperty.Register();. So yeah, I can't find the way to solve my problem..

我也想说些什么,如果DependencyProperty.Register();将存在于 Xamarin.Forms 中,那么这意味着我必须为每个值执行此操作吗?因为,如果必须通过 XAML绑定逻辑设置每个值,那么它将无法正常工作,我必须注册每个值,不是吗?

I also though about something, if DependencyProperty.Register(); would exists in Xamarin.Forms, then it means I would have to do it for each values? Because, if every value has to be set by a XAML binding logic, it would not work, I would have to register every value, doesn't it?

很抱歉,如果我不清楚,但对这个问题我很迷失..请不要犹豫,询问更多详细信息,在此先感谢!

I'm sorry if I'm not clear, but I'm so lost about this problem.. Please, do not hesitate to ask for more details, thank in advance !

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

MapTest.PolylineAddressPoints = AddressPointList;  

推荐答案

这里有多个问题:

  • 为什么使用Xaml时永远不会调用属性设置器?
  • 我可以正确定义BindableProperty吗?
  • 为什么绑定失败?

让我以不同的顺序回答他们.

Let me answer them in a different order.

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

The BindableProperty declaration is right, but could be improved by using an IList<string>:

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

但是属性访问器是错误的,并且应该只包含以下内容:

but the property accessor is wrong, and should only contains this:

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

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

I'll tell you why while answering the next question. But you want to invoke a method when the property has changed. In order to do that, you have to reference a propertyChanged delegate to CreateBindableProperty, like this:

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().

When setting a property with a BindablePrperty backing store from Xaml, the property accessors are bypassed and SetValue() is used directly.

在从代码或从Xaml定义Binding时,再次忽略属性访问器,并在需要修改属性时使用SetValue().并且,当调用SetValue()时,将在属性更改后执行propertyChanged委托(要完成此操作,请在属性更改之前调用propertyChanging).

When defining a Binding, both from code or from Xaml, property accessors are again bypassed and SetValue() is used when the property needs to be modified. And when SetValue() is invoked, the propertyChanged delegate is executed after the property has changed (to be complete here, propertyChanging is invoked before the property change).

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

You might wonder why bother defining the property if the bindable property is only used by xaml, or used in the context of Binding. Well, I said the property accessors weren't invoked, but they are used in the context of Xaml and XamlC:

  • 可以在属性上定义[TypeConverter]属性,并且将使用
  • 打开XamlC,可以使用属性签名在编译时推断BindablePropertyType.
  • a [TypeConverter] attribute can be defined on the property, and will be used
  • with XamlC on, the property signature can be used to infer, at compile time, the Type of the BindableProperty.

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

So it's a good habit to always declare property accessors for public BindableProperties. ALWAYS.

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

As you're using CustomMap as both View and ViewModel (I won't tell the Mvvm Police), doing this in your constructor should be enough:

BindingContext = this; //no need to prefix it with base.

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

As you're doing it already, your Binding should work once you've modified the BindableProperty declaration in the way I explained earlier.

这篇关于忽略绑定初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆