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

14

我在Xamarin Forms中的自定义视图中,无法将数据绑定到包含页面的视图模型上,希望能得到帮助。

我的自定义视图非常简单,只是一对表示键值对的标签:

<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期间显式设置Labels的Text属性:

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

再试了一遍,这并没有帮助,设置器代码似乎从未被执行过(我在上面放了一个断点但它并未被触发)

如果我添加一个开箱即用的控件,例如一个直接绑定到页面属性的标签,它将正确显示:

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

有人能解释一下为什么会发生这种情况吗(或者更确切地说,为什么没有发生)?

2个回答

27
请使用以下方式,不要在自定义控件内部分配绑定。:
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>

将属性(如Value)视为对BindableProperty(ValueProperty)的引用。如果你在Value setter内执行某些操作,BindableProperty不会收到通知,并且相反地,如果你使用BindableProperty(分配/更改ValueProperty),则Value setter不会被调用。

如果您想处理PropertyChanged,可以使用OnPropertyChanged进行覆盖,或在创建BindableProperty时作为附加参数使用Actions。


1
那正是我所需要的,谢谢。对于有很多可绑定属性的自定义视图可能会变得有点麻烦,但当我到达那个点时,我会考虑重构。 - MikeW
很遗憾,propertyChanged从BindableProperty变成了静态方法。自定义属性的整个意义在于重复使用,而这个静态方法只能使用一个自定义元素。但是你的解决方案非常好用。 - dpineda
1
谢谢!我在两天后找到了一个适当的解决方案来解决这个问题。 - Javier Sanchez

4

我通过以下方式使其正常工作:

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

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

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

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


这是正确的答案! - Thanh Nguyen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接