在 Xamarin.Forms 中绑定自定义视图

Binding a Custom View In Xamarin.Forms

我在将 Xamarin 表单中的自定义视图中的数据绑定到包含页面的视图模型时遇到问题。

我的自定义View很简单,一对标签代表一个键值对:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="KeyValueView">
    <Grid VerticalOptions="Start">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Label x:Name="KeyLabel" Text="{Binding Key}"  Grid.Column="0" HorizontalOptions="Start" />
        <Label x:Name="ValueLabel" Text="{Binding Value}" Grid.Column="1" HorizontalOptions="EndAndExpand" />
    </Grid>
</ContentView>

后面的代码:

public partial class KeyValueView : ContentView
{
    public KeyValueView()
    {
        InitializeComponent();
        this.VerticalOptions = LayoutOptions.Start;
        this.BindingContext = this;
    }

    public static readonly BindableProperty ValueProperty =
                BindableProperty.Create<KeyValueView, string>(w => w.Value, default(string));

    public string Value
    {
        get {return (string)GetValue(ValueProperty);}
        set {SetValue(ValueProperty, value);}
    }

    public static readonly BindableProperty KeyProperty =
        BindableProperty.Create<KeyValueView, string>(w => w.Key, default(string));

    public string Key
    {
        get {return (string)GetValue(KeyProperty);}
        set {SetValue(KeyProperty, value);}
    }
}

这在页面中消耗如下:

<views:KeyValueView Key="Order Number" Value="{Binding document_number}" />

问题是键字符串按预期显示,但值字符串不是。 我曾尝试在 document_number 属性 上强制执行 PropertyChanged 事件,但这没有帮助。 我还尝试在自定义视图的 Key/Value 属性的 setter 期间在标签上显式设置文本 属性:

public string Key
    {
        get {return (string)GetValue(KeyProperty);}
        set {
            SetValue(KeyProperty, value);
            KeyLabel.Text = value;
        }
    }

同样这没有帮助,setter 代码似乎从未执行过(我在上面放置了一个断点但没有命中)

如果我添加开箱即用的控件,例如直接绑定到页面中 属性 的标签,则可以正确显示:

<Label Text="{Binding document_number}"/>
<views:KeyValueView Key="Order Number" Value="{Binding document_number}" />

谁能解释为什么会发生(或者更确切地说没有发生)?

不要在自定义控件内部分配绑定。使用这个:

public partial class KeyValueView : ContentView
{
    public KeyValueView()
    {
        InitializeComponent();
        this.VerticalOptions = LayoutOptions.Start;
    }

    public static readonly BindableProperty ValueProperty =
        BindableProperty.Create<KeyValueView, string>(w => w.Value, default(string));

    public string Value
    {
        get {return (string)GetValue(ValueProperty);}
        set {SetValue(ValueProperty, value);}
    }

    public static readonly BindableProperty KeyProperty =
        BindableProperty.Create<KeyValueView, string>(w => w.Key, default(string));

    public string Key
    {
        get {return (string)GetValue(KeyProperty);}
        set {SetValue(KeyProperty, value);}
    }
    protected override void OnPropertyChanged(string propertyName)
    {
        base.OnPropertyChanged(propertyName);

        if (propertyName == ValueProperty.PropertyName)
        {
            ValueLabel.Text = Value;
        }
        if (propertyName == KeyProperty.PropertyName)
        {
            KeyLabel.Text = Key;
        }
    }
}

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="KeyValueView">
    <Grid VerticalOptions="Start">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Label x:Name="KeyLabel" Grid.Column="0" HorizontalOptions="Start" />
        <Label x:Name="ValueLabel" Grid.Column="1" HorizontalOptions="EndAndExpand" />
    </Grid>
</ContentView>

将属性(例如值)视为对 BindableProperty (ValueProperty) 的引用。如果你在 Value setter BindableProperty 中做了一些事情, BindableProperty 将不会收到通知,相反,如果你在 BindableProperty (assign/change ValueProperty) 中做了一些事情 - 属性 Value setter 不会被调用。

如果你想处理 PropertyChanged,你有一个覆盖 (OnPropertyChanged) 或操作(作为创建 BindableProperty 时的附加参数)。

我能够通过

使它工作
public KeyValueView()
{
    InitializeComponent();
    this.VerticalOptions = LayoutOptions.Start;
    this.Content.BindingContext = this;
}

然后在 xaml.cs 中为您使用自定义视图的视图执行此操作:

public ParentView()
{
    InitializeComponent();
    BindingContext = this;
}

对于给我带来问题的条目字段,我必须确保将 defaultBindingMode 参数设置为 TwoWay。