我正在尝试使用服务调用返回的结果填充列表视图。
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));
}
}
}
}
答案 0 :(得分:0)
问题在于,对ObservableCollection进行动态更改(例如,添加/删除项目)不会为RepeaterView类中的ItemSourceProperty触发PropertyChangedEvent,因为它仍然是同一对象。分配新实例将触发事件,依此类推,请调用ItemsChanged方法。
一种解决方案是订阅ObservableCollection的CollectionChanged事件(see reference),如果该项目的项目发生更改(例如,添加/删除或清除整个集合),则将触发该事件,然后调用ItemsChanged方法更新视图
此RepeaterView实现可与ObservableCollection配合使用,并在更改后完美地更新视图。
希望我的回答仍然有帮助!