Xamarin Forms:RepeaterView不绑定动态数据,但与listView一起工作



我正试图用服务调用返回的结果填充列表视图。

PFB我的XAML代码:

<StackLayout Orientation="Vertical" BackgroundColor="#FFFFFF">
<!-- Doesn't Work -->
<repeater:RepeaterView ItemsSource="{Binding DashboardItems}">
<repeater:RepeaterView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Title}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</repeater:RepeaterView.ItemTemplate>
</repeater:RepeaterView>
<!-- Works -->
<ListView ItemsSource="{Binding DashboardItems}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Title}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>

ViewModel:

public class DashboardSummaryViewModel : BaseViewModel, System.ComponentModel.INotifyPropertyChanged
{
public ObservableCollection<DashboardItem> DashboardItems { get; set; } = new ObservableCollection<DashboardItem>();
public override void Init()
{
base.Init();

GetSummary();
}
private void GetSummary(){
// If I update DashboardItems value here, it even works with repeaterView control 
var paywithSdk = DependencyService.Get<IPaywithSDK>();
if (paywithSdk != null)
{
paywithSdk.SetListener(new PaywithSDKListener
{
OnSuccess = user =>
{
if (user != null)
{
user.DateUpdated = DateTime.Now;
LoadSummaryDetails(user);
}
},
OnError = error =>
{
var user = UserDetails.CreateDefault();
user.ResponseString = DataContractSerialiser.JsonSerialize(error);
//RefreshUserDetails(user);
}
});
}
}
private void LoadSummaryDetails(UserDetails user)
{
DashboardItem dashboardItem = new DashboardItem();
dashboardItem.Tile = new DashboardTile();
dashboardItem.Tile.Title = "Wallet";
dashboardItem.Tile.ItemDetailsPage = AppPage.PROFILE_DETAILS;
dashboardItem.SubTitle = new DashboadTileContent();
dashboardItem.SubTitle.IsVisible = false;
dashboardItem.ItemDetailsPageMessage = new DashboadTileContent();
dashboardItem.ItemDetailsPageMessage.Message = "Click through to view your transactions";
dashboardItem.ItemDetailsPageMessage.IsVisible = true;
dashboardItem.StatusType = new DashboadTileContent();
dashboardItem.StatusType.Message = "Current balance";
dashboardItem.StatusType.IsVisible = true;
dashboardItem.StatusValue = new DashboadTileContent();
dashboardItem.StatusValue.Message = user.TotalBalance.ToString();
dashboardItem.StatusValue.IsVisible = true;
dashboardItem.SummaryItems = new DashboardTileSummaryItems();
dashboardItem.SummaryItems.Items = new List<DashboardTileSummaryItem>();
foreach(var item in WalletSummaryDetails.UserSalPacks){
DashboardTileSummaryItem dashboardTileSummaryItem = new DashboardTileSummaryItem();
dashboardTileSummaryItem.DisplayName = item.DisplayName;
dashboardTileSummaryItem.Value = Convert.ToString(item.Balance);
dashboardItem.SummaryItems.Items.Add(dashboardTileSummaryItem);
}
dashboardItem.TileSubLinks = new DashboardTileSubLinks();
dashboardItem.TileSubLinks.Links = new List<DashboardTileSubLink>(){
new DashboardTileSubLink(){DisplayName = "View Offers", LinkDetailsPage = AppPage.PROFILE_DETAILS},
new DashboardTileSubLink(){DisplayName = "Report Lost/Stolen", LinkDetailsPage = AppPage.PROFILE_DETAILS}
};
dashboardItem.TileSubLinks.IsVisible = true;
WallterDashboardItem = dashboardItem;
DashboardItems.Add(dashboardItem);
}
}

DashboardItems是试图在XAML中绑定的集合成员属性。

此属性值在"paywithSdk.SetListener"调用的OnSuccess回调函数中更新。使用更新的值,数据不会绑定到repeaterView控件。中继器视图不显示绑定到视图的值。

但是,如果我将此集合属性绑定到ListView控件,它就可以工作,并且它会像上面的XAML代码中那样获得更新的值。

我的问题是,我想用我的自定义stackLayout控件自定义listItem元素,我想使用repeaterView而不是ListView控件。

即使使用repeaterView,如果集合值在同一线程调用中而不是在回调方法调用中更新,则该值也会被绑定。但我需要将repeaterView控件与"paywithSdk.SetListener"OnSuccess回调方法中更新的数据绑定。

请告诉我如何使用repeaterView控件绑定更新的数据。

PFB中继器视图代码:

namespace XamarinForms.Plugin.Repeater
{
public class RepeaterView : StackLayout
{
public static readonly BindableProperty ItemTemplateProperty = BindableProperty.Create(
nameof(ItemTemplate),
typeof(DataTemplate),
typeof(RepeaterView),
default(DataTemplate));
public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(
nameof(ItemsSource),
typeof(ICollection),
typeof(RepeaterView),
null,
BindingMode.OneWay,
propertyChanged: ItemsChanged);
public RepeaterView()
{
Spacing = 0;
}
public ICollection ItemsSource
{
get => (ICollection)GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public DataTemplate ItemTemplate
{
get => (DataTemplate)GetValue(ItemTemplateProperty);
set => SetValue(ItemTemplateProperty, value);
}
protected virtual View ViewFor(object item)
{
View view = null;
if (ItemTemplate != null)
{
var content = ItemTemplate.CreateContent();
view = content is View ? content as View : ((ViewCell)content).View;
view.BindingContext = item;
}
return view;
}
private static void ItemsChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = bindable as RepeaterView;
if (control == null) return;
control.Children.Clear();
var items = (ICollection)newValue;
if (items == null) return;
foreach (var item in items)
{
control.Children.Add(control.ViewFor(item));
}
}
}

}

问题是,对ObservableCollection进行动态更改(例如添加/删除项(不会激发RepeaterView类中ItemSourceProperty的PropertyChangedEvent,因为它仍然是同一个对象。分配一个新实例会引发事件,依此类推,调用ItemsChanged方法。

一个解决方案是订阅ObservableCollection的CollectionChanged事件(请参阅参考(,如果其项发生更改(例如添加/删除或清除整个集合(,就会触发该事件,然后调用ItemsChanged方法来更新视图。

此RepeaterView实现与ObservableCollection配合良好,并在更改后完美地更新视图。

希望我的回答仍然有帮助!

相关内容

最新更新