Xamarin Forms 自定义控件 BindableProperty propertyChanged not Firing
Xamarin Forms Custom Control BindableProperty propertyChanged not Firing
尝试设置一个非常简单的自定义控件来处理在标签中使用项目符号时的对齐方式。问题是,传递到自定义控件的 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="•" />
<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。
解决方案:
我仍然建议您使用数据绑定,因为您已将其设置为 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>;
//...
}
尝试设置一个非常简单的自定义控件来处理在标签中使用项目符号时的对齐方式。问题是,传递到自定义控件的 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="•" />
<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。
解决方案:
我仍然建议您使用数据绑定,因为您已将其设置为 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>;
//...
}