我正在开发一个移动应用程序,它有一个 API,我可以调用它来获取数据,大多数端点都被分页并返回以下对象:
public class PagedResult<T>
{
public List<T> Data { get; private set; }
public PagingInfo Paging { get; private set; }
public PagedResult(IEnumerable<T> items, int pageNo, int pageSize, long totalRecordCount)
{
Data = new List<T>(items);
Paging = new PagingInfo
{
PageNo = pageNo,
PageSize = pageSize,
TotalRecordCount = totalRecordCount,
PageCount = totalRecordCount > 0
? (int)Math.Ceiling(totalRecordCount / (double)pageSize)
: 0
};
}
}
我已经构建了一个可以选择分页结果的控件,该控件显示当前页面项目的列表并允许用户在其他页面中移动(如下图所示)。
我已经为这个控件建立了一个概念证明,但是我遇到了一个小但非常烦人的绊脚石。
MyPagedResult<T>
是通用的,但PagedItemSource
我的列表视图不是。我构建了具有可绑定属性的控件:DataTemplate
, PagedItemSource
& LoadPageCommand
。控件本身决定加载哪个页面并自行执行该命令(稍后我可能会公开此值,但现在不需要)。
在构建控件时,我必须初始化PagedResult<T>
,但不必担心泛型,我只是将其放入PagedResult<object>
并在我的视图模型中执行相同操作。现在,我希望这个列表是通用的,我构建这个控件的部分原因是通用和抽象,因为它对控件的分页负责。然而,由于我的 API 模型使用泛型,我被卡住了!
我无法使用通用 T 初始化我的控件:
public partial class PaginationControl<T>: ContentView
{
...
}
将意味着 C# 编译器开始对我大喊大叫,实际上整个班级都在发疯。我的绑定属性显示警告:Static field in generic type
。这就是为什么我只是用作<object>
列表的类型,不幸的是,绑定在以下情况下不起作用:
查看模型
public PagedResult<MyObject> PagedItemSource { get; set; }
控制
public static readonly BindableProperty PagedItemSourceProperty = BindableProperty.Create(
nameof(PagedItemSource),
typeof(PagedResult<object>),
typeof(PaginationControl),
defaultValue: null,
propertyChanged: (bindable, oldVal, newVal) => ((PaginationControl)bindable).OnPagedItemSourceChanged((PagedResult<object>)newVal)
);
如果我的视图模型的数据也是类型,它会起作用<object>
但是那没有用,因为现在我需要在我的视图模型中跟踪我的数据类型......
我想出了一个 hacky 工作,以便我可以使用该应用程序,但它很愚蠢,感觉很脏,我讨厌它......
我的技巧是在我的视图模型中有第二个属性,它只接受当前PagedResult<T>
并将其转换为PagedResult<object>
,并将此属性绑定到控件。(抱歉,您必须阅读此内容)
我去搜索了 Xamarin.Forms 源代码,看看他们是如何做到这一点的,ListView
因为它本质上是相同的问题,并且他们ListView
接受任何通用对象。不幸的是,我发现 src 令人难以置信的混乱并且没有学到任何可以帮助解决我的问题的东西(我看到ItemView<Cell>
那ItemSource
是一个IEnumerable
但我无法弄清楚他们是如何设置T
这个的......
任何帮助将不胜感激,我可能以错误的方式看待这个!