Xamarin 窗体自定义控件 BindableProperty 属性更改未触发 [英] Xamarin Forms Custom Control BindableProperty propertyChanged not Firing

查看:40
本文介绍了Xamarin 窗体自定义控件 BindableProperty 属性更改未触发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试设置一个非常简单的自定义控件来处理在标签中使用项目符号时的对齐方式.问题是,传递给自定义控件的 Span 没有被识别,并且内容没有被呈现(并且 propertyChanged 函数没有被触发).我错过了什么?

Trying to set up a very simple custom control to handle alignment when using bullet points in a label. The issue is, the Spans passed into the custom control are not being recognized and the content isn't getting rendered (and the propertyChanged function isn't firing). What am I missing?

XAML:

<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
    x:Class="Sample.Controls.BulletPointItem"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:d="http://xamarin.com/schemas/2014/forms/design"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <ContentView.Content>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="10" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Label x:Name="BulletPoint" Text="&#x2022;" />
            <Label x:Name="LabelContent" Grid.Column="1" />
        </Grid>
    </ContentView.Content>
</ContentView>

代码隐藏:

[ContentProperty(nameof(Spans))]
public partial class BulletPointItem : ContentView
{
    // todo add bindable props for bullet point size and color, or even which character to use as the bullet point!
    public static readonly BindableProperty SpansProperty =
        BindableProperty.Create(
            nameof(Spans),
            typeof(ObservableCollection<Span>),
            typeof(BulletPointItem),
            new ObservableCollection<Span>(),
            BindingMode.OneWay,
            propertyChanged: OnSpansChanged);

    public BulletPointItem()
    {
        InitializeComponent();
    }

    public ObservableCollection<Span> Spans
    {
        get => (ObservableCollection<Span>)GetValue(SpansProperty);
        set => SetValue(SpansProperty, value);
    }

    private static void OnSpansChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control = (BulletPointItem)bindable;
        var newSpansValue = (ObservableCollection<Span>)newValue;
        var formattedString = new FormattedString();

        if (control == null)
            return;

        if (newSpansValue == null || newSpansValue.Count == 0)
        {
            control.LabelContent.FormattedText = formattedString;
            return;
        }

        foreach (var span in newSpansValue)
        {
            formattedString.Spans.Add(span);
        }

        control.LabelContent.FormattedText = formattedString;
    }
}

尝试使用:

                            <controls:BulletPointItem>
                                <Span Text="Span 1." />
                                <Span FontAttributes="Italic" Text="Span 2." />
                            </controls:BulletPointItem>

推荐答案

原因:Spans 是一个 ObservableCollection.所以如果你想设置它的值,你应该在xaml中定义一个Collection,而不是直接列出Span.

Cause: Spans is an ObservableCollection. So if you want to set the value of it , you should define a Collection in xaml instead of list the Span directly .

解决方案:

我仍然建议您应该使用数据绑定,因为您已将其设置为 BindableProperty .

I still suggest that you should use data-binding since you have set it as a BindableProperty .

<controls:BulletPointItem BackgroundColor="LightBlue" Spans="{Binding Spans}">

在代码后面或 ViewModel

public static readonly BindableProperty SpansProperty =
        BindableProperty.Create(
        nameof(Spans),
        typeof(ObservableCollection<Span>),
        typeof(BulletPointItem),
        defaultValueCreator: bindable => new ObservableCollection<Span>(),
        propertyChanged: OnSpansChanged);

public ObservableCollection<Span> spans { get; set; }

spans = new ObservableCollection<Span>() {

      new Span(){Text="Span1" },
      new Span(){Text="Span2",FontAttributes=FontAttributes.Italic }
};

当您想要添加或删除项目时,这将更加灵活.

This will be more flexible when you want to add or remove the items from it .

当您完全从 XAML 设置跨度时.它会将项目添加到 跨度.但是只有在您为其设置新值时才会调用方法 OnSpansChanged.因此,您可以处理方法 CollectionChanged 中的逻辑.每次向 Spas 添加新项目时都会调用它.

When you set the Spans purely from XAML .It will add items to the Spans.But the method OnSpansChanged will only been invoked when you set it a new value . So you can handle the logic in method CollectionChanged .It will been called each time you add a new item to Spans.

public BulletPointItem()
{
  InitializeComponent();
 
  Spans.CollectionChanged += Spans_CollectionChanged;
}

// this method will been invoked 2 times if you add two span in xaml
private void Spans_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
   var collection = sender as ObservableCollection<Span>;
  //...  
}

这篇关于Xamarin 窗体自定义控件 BindableProperty 属性更改未触发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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