我们是 Xamarin 的新手。我们在将 Web 服务的响应数据绑定(bind)到 ListView 时遇到问题。
我们进行了调试,可以看到 Web 服务已成功响应数据,但它从未被填充。
有什么想法吗?
这一定是我们遗漏的一件小事。我们已经成功地使用其他 View (在项目的其他部分)显示数据中的单个条目,但不在 IEnumerable<>
中。或List<>
代码如下:
查看 - RoundsPage.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewModels="clr-namespace:AthlosifyMobile.ViewModels"
x:Class="AthlosifyMobile.Views.RoundsPage">
<ContentPage.BindingContext>
<viewModels:RoundsViewModel />
</ContentPage.BindingContext>
<StackLayout>
<Entry Text="{Binding AccessToken}" />
<Button Command="{Binding GetRoundsCommand}" Text="Get all rounds" />
<Label Text="Rounds: "></Label>
<ListView ItemsSource="{Binding Rounds}" HasUnevenRows="true" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="Round 1:"></Label>
<Label Text="{Binding Name}"></Label>
<Label Text="{Binding DailyHandicap}"></Label>
<Label Text="{Binding PlayedUTC}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>`
ViewModel - RoundsViewModel.cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using System.Windows.Input;
using AthlosifyMobile.Annotations;
using Xamarin.Forms;
using AthlosifyMobile.Services;
using AthlosifyMobile.Models;
namespace AthlosifyMobile.ViewModels
{
public class RoundsViewModel : INotifyPropertyChanged
{
ApiServices _apiServices = new ApiServices();
public event PropertyChangedEventHandler PropertyChanged;
private IEnumerable<Round> _rounds;
public string AccessToken { get; set; }
public IEnumerable<Round> Rounds
{
get
{
return _rounds;
}
set
{
_rounds = value;
OnPropertyChanged();
}
}
public ICommand GetRoundsCommand
{
get
{
return new Command(async() =>
{
Rounds = await _apiServices.GetRoundsAsync(AccessToken);
});
}
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
模型 - Course.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace AthlosifyMobile.Models
{
public class Round : EntityBase
{
public Guid RoundID { get; set; }
public Guid UserID { get; set; }
public Guid RoundCategoryID { get; set; }
public Guid CourseID { get; set; }
public string Name { get; set; }
public string Notes { get; set; }
public int DailyHandicap { get; set; }
public DateTime PlayedUTC { get; set; }
public RoundCategory RoundCategory { get; set; }
public Course Course { get; set; }
public ICollection<RoundHole> RoundHoles { get; set; }
}
public abstract class EntityBase
{
public DateTime CreatedUTC { get; set; }
public DateTime LastModifiedUTC { get; set; }
}
}
服务 - apiservices.cs:
using AthlosifyMobile.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace AthlosifyMobile.Services
{
public async Task<IEnumerable<Round>> GetRoundsAsync(string accessToken)
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var json = await client.GetStringAsync("http://localhost:5609/api/Rounds");
var list = JsonConvert.DeserializeObject<IEnumerable<Round>>(json);
return list;
}
}
}
最佳答案
您需要诊断这是否是 View 连接到 ViewModel 时出现的问题,或者您的数据服务是否无法正常工作。不管怎样,您应该采取一些措施来解决这个问题!
首先,您正在使用 IEnumerable
,相反,您应该使用 ObservableCollection<T>
。您应该始终使用 ObservableCollection<T>
对于绑定(bind) ListView 。 xamarin 文档 here 对此进行了解释(当内容更改和更新时,它们会自动通知 View )。
所以你应该做出这样的改变:
public ObservableCollection<Round> Rounds { get; }
接下来您应该验证绑定(bind)是否正确。如果您不熟悉 xamarin,我不建议您直接使用实时数据。首先,您应该尝试向 View 模型添加一些静态对象并尝试绑定(bind)它们!
断开您的 API 代码并调用一个方法来创建您的一些 Round
对象。这是一个示例方法(我在设计 ListViews UI 时一直使用此类方法)。
public RoundsViewModel()
{
Rounds = CreateSampleData();
}
private ObservableCollection<Round> CreateSampleData()
{
ObservableCollection<Round> dummyData = new ObservableCollection<Round>();
dummyData.Add(new Round() { Name="User", handicap=1, PlayedUTC=DateTime.Now });
dummyData.Add(new Round() { Name="User", handicap=1, PlayedUTC=DateTime.Now });
dummyData.Add(new Round() { Name="User", handicap=1, PlayedUTC=DateTime.Now });
return dummyData;
}
此时,您将在 ListView 中看到项目,这意味着您的 API 代码/INotifyPropertyChanged
的实现存在问题。 。如果您没有看到任何内容,则可能存在绑定(bind)问题,需要验证您的 View 是否确实连接到 View 模型。
Mvvm 助手
看到这些代码让我为你感到非常遗憾,你绝对应该考虑使用 MVVM 助手,例如 Prism 或 MVVMCross。我个人使用 Prism,它提供了 ViewModelBase
所有 ViewModel 都继承自它。这意味着所有 INotifyPropertyChanged
代码隐藏在远离您的地方(更少的样板文件)。它还具有依赖服务,这意味着将 View 连接到 View 模型就像在 app.cs 中注册一样简单。
如果你对棱镜感兴趣,请观看this video with Brian Lagunas看看 Prism 能为您做什么!
更新:除了 Prism 之外,现在还有一些有用的库可以帮助解决 MVVM 问题。 Refractored.MVVMHelpers和 Xamarin.CommunityToolkit两者都包含一个重要的对象:ObservableRangeCollection
.
使用ObservableCollection
的ALL代码应替换为 ObservableRangeCollection
,它是一个重要的对象,并且此时确实属于 Microsoft 维护的命名空间。它为更新更大的集合带来了性能优势,并减少了更新ObservableCollection
时对大量样板的需求。
关于c# - Xamarin.Forms ListView 绑定(bind)问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51576468/