【问题标题】:Xamarin Forms Custom Control BindableProperty propertyChanged not FiringXamarin Forms 自定义控件 BindableProperty propertyChanged not Firing
【发布时间】:2020-01-30 14:14:39
【问题描述】:

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

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>

【问题讨论】:

    标签: c# xaml xamarin.forms controls


    【解决方案1】:

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

    解决方案:

    我仍然建议您应该使用数据绑定,因为您已将其设置为 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 }
    };
    

    当您想从中添加或删除项目时,这将更加灵活。

    更新

    当您完全从 XAML 设置 Spans 时。它会将项目添加到 Spans。但是方法 OnSpansChanged 只有在您为其设置新值时才会被调用。 所以你可以在 CollectionChanged 方法中处理逻辑。每次向 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>;
      //...  
    }
    

    【讨论】:

    • 嗨卢卡斯,谢谢。这确实有效,但我怎样才能完全从 XAML 设置 Spans?是的,我喜欢绑定它们的选项,但也希望它在静态意义上也能工作(纯粹来自 XAML)。
    • 嘿卢卡斯,是的,这绝对是我错过的一件大事……太累了,无法理解。那,我正在设置一个默认值(但我应该一直使用 DefaultValueCreator 为 BulletPointItem 的每个实例创建一个新的 ObservableCollection,因为通过设置 DefaultValue,它只会创建一个实例,这将是在所有 BulletPointItems 之间共享。我也更新了它,现在我可以开始了。我想说在你的答案中包含这个花絮,让其他人看到,我会将其标记为已接受:defaultValueCreator: bindable => new ObservableCollection() 谢谢!
    • 感谢您的建议!我已经改进了我的答案,你现在可以接受了。如果您认为我的答案应该改进,您可以直接编辑它:)
    猜你喜欢
    • 2018-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 1970-01-01
    相关资源
    最近更新 更多