自定义控件上的BindableProperty问题

时间:2018-11-28 23:53:30

标签: xamarin.forms

我在将文本绑定到自定义控件内的标签时遇到问题。

我已经进行了以下控制:

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Frida3.Components.TestView">
  <ContentView.Content>
      <StackLayout>
          <Label Text="{Binding Text}" />
      </StackLayout>
  </ContentView.Content>
</ContentView>

具有以下代码:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestView : ContentView
{
    public TestView ()
    {
        InitializeComponent ();
        BindingContext = this;
    }

    public static readonly BindableProperty TextProperty =
        BindableProperty.Create("Text", typeof(string), typeof(TestView), default(string));

    public string Text
    {
        get => (string) GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }
}

在使用控件和绑定来设置Text属性时,不显示任何内容。下面是显示结果的一些示例代码:

<!-- Shows that the LoginText binding contains value -->
<Label Text="{Binding LoginText}" BackgroundColor="BurlyWood"/>
<!-- Nothing shown with same binding -->
<components:TestView Text="{Binding LoginText}" BackgroundColor="Aqua" />
<!-- Works without binding -->
<components:TestView Text="This is showing" BackgroundColor="Yellow" />

这是结果:

Screenshot

2 个答案:

答案 0 :(得分:1)

我找到了解决方案。基本上,我给控件命名(adb shell idme print | grep "^serial" ),然后将源添加到数据绑定中,例如:x:Name="this"。 通过这些更改,我可以删除Source={x:Reference this}

所以最终的xaml会像这样:

BindingContext = this;

我想知道是否有一种更简单的方法,因此我不必向使用BindableProperty的每个孩子添加源代码。

答案 1 :(得分:1)

XAML

让我们按照如下所示使用自定义控件的XAML:

<ContentView 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="Frida3.Components.TestView">
    <ContentView.Content>
        <StackLayout>
            <Label Text="{Binding Text}" />
        </StackLayout>
    </ContentView.Content>
</ContentView>

向您的自定义控件添加绑定会为您的应用程序增加另一级别的复杂性,如果使用过多,则可能会妨碍应用程序的性能。最好将Label重写为:

<Label x:Name="MyLabel"/>

现在,Label可以在后面的代码中访问。

隐藏代码

您已在问题中正确设置了属性,如下所示:

public static readonly BindableProperty TextProperty =
    BindableProperty.Create(
        "Text", 
        typeof(string), 
        typeof(TestView), 
        default(string));

public string Text
{
    get => (string) GetValue(TextProperty);
    set => SetValue(TextProperty, value);
}

您可以从构造函数中删除BindingContext = this;,因为您将不会使用任何绑定。

在您的TextProperty中,我们将为propertyChanged参数添加一个事件,并定义该事件:

public static readonly BindableProperty TextProperty =
    BindableProperty.Create(
        propertyName: nameof(Text), 
        returnType: typeof(string), 
        declaringType: typeof(TestView), 
        defaultValue: default(string),
        propertyChanged: HandleTextPropertyChanged); // Property-changed handler!!

public string Text
{
    get => (string) GetValue(TextProperty);
    set => SetValue(TextProperty, value);
}

// Handler for when the Text property changes.
private static void HandleTextPropertyChanged(
    BindableObject bindable, object oldValue, object newValue)
{
    var control = (TestView)bindable;
    if (control != null)
    {
        control.MyLabel.Text = (string)newValue;
    }
}

这是怎么回事?本质上,您已经告诉应用程序

  

“当Text的{​​{1}}属性发生更改时,请设置TestView   属性Text更改为新的字符串值”。

您的代码现在应如下所示:

MyLabel

您现在可以像这样调用自定义视图:

// BindableProperty for your Text property
public static readonly BindableProperty TextProperty =
    BindableProperty.Create(
        propertyName: nameof(Text), 
        returnType: typeof(string), 
        declaringType: typeof(TestView), 
        defaultValue: default(string),
        propertyChanged: HandleTextPropertyChanged); // Property-changed handler!!

// Text property of you TestView
public string Text
{
    get => (string) GetValue(TextProperty);
    set => SetValue(TextProperty, value);
}

// Constructor
public TestView ()
{
    InitializeComponent ();
}

// Handler for when the Text property changes.
private static void HandleTextPropertyChanged(
    BindableObject bindable, object oldValue, object newValue)
{
    var control = (TestView)bindable;
    if (control != null)
    {
        control.MyLabel.Text = (string)newValue;
    }
}

那里有!没有绑定,只有老式事件。