如何解决当在 ObservableCollection 中引用该属性时,为什么此 Binding 不起作用?
我有以下问题,我无法理解。我是 Xamarin 的新手,我已经研究这个特定问题有一段时间了。
TL;DR: 我有一个 MyGroups[] 数组,它由 XAML 中的中继器使用。中继器使用的 DataTemplate 有一个 ObservableCollection,用 XAML 填充。将 MyGroups 的属性之一与 Description.Title 绑定不起作用,但是在描述集合之外使用相同的属性可以正常工作。
长话:
假设我们有一个中继器,它由虚拟机的 MyGroups[] 属性填充。 Repeater 和 Models:Group 看起来像这样:
<Grial:Repeater ItemTemplate = "{ DynamicResource GroupDataTemplate }"
ItemsSource = "{ Binding MyGroups }"/>
namespace MyApp.Models
{
public class Group
{
public string MyProperty
{
get;
set;
}
public string MyOtherProperty
{
get;
set;
}
}
}
此中继器获取以下数据模板:
<DataTemplate x:Key = "GroupDataTemplate">
<Cards:CardTemplate x:DataType = "Models:Group">
<StackLayout HorizontalOptions = "Center"
VerticalOptions = "Center">
<Label>
<Label.Text>
<MultiBinding StringFormat="{} {0} {1}"> //<---- this works
<Binding Path = "MyProperty" />
<Binding Source = "{ x:Static Strings:AppResources.MyString }"/>
</MultiBinding>
</Label.Text
</Label>
</StackLayout>
<Cards:CardTemplate.Descriptions>
<Models:Description>
<Models:Description.Title>
<MultiBinding StringFormat="{} {0} {1}"> //<---- this value is always null
<Binding Path = "MyProperty" />
<Binding Source = "{ x:Static Strings:AppResources.MyString }"/>
</MultiBinding>
</Models:Description.Title>
</Models:Description>
<Models:Description>
<Models:Description.Title>
<MultiBinding StringFormat="{} {0} {1}"> //<---- this value is always null
<Binding Path = "MyOtherProperty" />
<Binding Source = "{ x:Static Strings:AppResources.MyString }"/>
</MultiBinding>
</Models:Description.Title>
</Models:Description>
</Cards:CardTemplate.Descriptions>
</Cards:CardTemplate>
</DataTemplate>
Cards:CardTemplate 看起来像这样:
<Grial:CardView ...>
...
<Grial:GridView RowSpacing = "16"
Grid.Row = "1"
ColumnCount = "2"
ItemsSource = "{ Binding Source={ RelativeSource AncestorType={ x:Type Cards:CardTemplate } },Path=Descriptions }">
<Grial:GridView.ItemTemplate>
<DataTemplate x:Name = "x_cardItemsDescriptionTemplate">
<StackLayout Spacing = "5"
Orientation = "Horizontal">
<Label VerticalOptions = "Center"
Text = "{ Binding Source={ RelativeSource AncestorType={ x:Type Models:Description } },Path=Icon }"/>
<Label VerticalOptions = "Center"
Text = "{ Binding Source={ RelativeSource AncestorType={ x:Type Models:Description } },Path=Description }"/>
</StackLayout>
</DataTemplate>
</Grial:GridView.ItemTemplate>
</Grial:GridView>
</Grial:CardView>
描述看起来像这样
using System;
using Xamarin.Forms;
public class Description
: BindableObject
{
public static readonly BindableProperty IconProperty = BindableProperty.Create( propertyName: nameof( Description.Icon ),returnType: typeof( string ),declaringType: typeof( Description ),defaultBindingMode: BindingMode.TwoWay,propertyChanged: Description.OnIconChanged );
public static readonly BindableProperty TitleProperty = BindableProperty.Create( propertyName: nameof( Description.Title ),propertyChanged: Description.OnTitleChanged );
public string Icon
{
get => (string)GetValue( IconProperty );
set => SetValue( property: IconProperty,value: value );
}
public string Title
{
get => (string)GetValue( TitleProperty );
set => SetValue( property: TitleProperty,value: value );
}
private static void OnIconChanged( BindableObject bindable,object old_value,object new_value )
{
try
{
( (Description)bindable ).Icon = new_value as string;
}
catch( Exception e )
{
...
}
}
private static void OnTitleChanged( BindableObject bindable,object new_value )
{
try
{
( (Description)bindable ).Title = new_value as string;
}
catch( Exception e )
{
...
}
}
}
我不明白的是为什么 {Binding Path=MyProperty} 对标签有效,但对描述无效。问题不在于 CardTemplate,因为每个硬编码或资源绑定的字符串都会分配给适当的元素。唯一的问题是绑定本身!
我尝试过的事情:
- BindingList 而不是 ObservableCollections
- 描述继承自 INotifyPropertyChanged/BindableObject
- 分配“Source={ RelativeSource AncestorType={ x:Type Models:Group } }”有或没有级别
- {Binding .MyProperty}、{Binding Models:Groups.MyProperty}、{Binding /MyProperty}
- 在组中实现 INotifyPropertyChanged
似乎没有任何效果,我不明白为什么?为什么 Label.Text 的值设置正确,而 Description.Title 没有。有什么我遗漏的吗?
解决方法
我找到了解决我的问题的方法。这不是我想要的 100%,但是,嗯,我猜已经足够接近了。
我无法实现的是使用 MultiBindings,但我并不严格需要在我的用例中连接多个字符串,所以我选择了 StringFormat。
<Cards:CardTemplate x:Name = "template">
<Cards:CardTemplate.Descriptions>
<Models:Description Title = "{ Binding Path=BindingContext.MyProperty,Source={ x:Reference Name=template },StringFormat=... }"/>
</Cards:CardTemplate.Descriptions>
</Cards:CardTemplate>
两个重要的点是 BindingContext.
的 Path=BindingContext.MyProperty
和引用容器视图的 Source
。由于 MyProperty
仅在 CardTemplate
级别可用,因此 CardTemplate
的所有子级都不知道它的存在。为了使它们可用,我们使用 Source
属性来引用模板,然后使用 BindingContext
来引用 ViewModel 容器的当前对象(在本例中为 MyGroup
)。由于我们现在可以访问每个 MyGroup
对象,我们可以调用其属性(在本例中为 MyProperty
),从而达到我们的目标。
为什么这不适用于 MultiBinding
我无法理解,但这已经足够了。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。