Я занимаюсь разработкой мобильного приложения, в котором есть 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
};
}
}
Я создал элемент управления, который может выбирать постраничные результаты, элемент управления отображает список элементов текущей страницы и позволяет пользователю перемещаться по другим страницам (на рисунке ниже).
Я создал доказательство концепции этого элемента управления, однако наткнулся на небольшой, но действительно раздражающий камень преткновения.
Мой PagedResult<T>
является общим, но PagedItemSource
для моего списка не является. Я создал элемент управления, чтобы иметь привязываемые свойства: DataTemplate
, PagedItemSource
& LoadPageCommand
. Сам элемент управления определяет, какая страница будет загружена, и сам выполнит эту команду (я могу выставить это значение позже, но пока это не нужно).
При создании элемента управления мне нужно было инициализировать PagedResult<T>
, однако вместо того, чтобы беспокоиться о дженериках, я просто превратил его в PagedResult<object>
и сделал то же самое в моей модели представления. Теперь я нахожусь в точке, где я хочу, чтобы этот список был универсальным, отчасти по той причине, что я построил этот элемент управления, чтобы он был универсальным и абстрактным, как большая ответственность за подкачку к элементу управления. Однако из-за того, что моя модель API использует универсальный, я застрял!
Я не могу инициализировать свой контроль с помощью Generic 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>
, однако это бесполезно, потому что теперь мне нужно отслеживать тип моих данных в моей модели представления ...
Я придумал хакерскую работу, чтобы я мог взломать приложение, но оно глупое и кажется грязным, и я его ненавижу ...
Мой хак - иметь второе свойство в моей модели представления, которое просто берет текущий PagedResult<T>
и преобразует его в PagedResult<object>
, и связывает это свойство с элементом управления. (Извините, что вам пришлось это прочитать)
Я пошел и получил трал для исходного кода Xamarin.Forms, чтобы посмотреть, как они сделали это для ListView
, поскольку это по сути та же проблема, и их ListView
принимает любой универсальный объект. К сожалению, я обнаружил, что src невероятно запутан, и не узнал ничего, что помогло бы решить мою проблему (я видел в ItemView<Cell>
, что ItemSource
- это IEnumerable
, но я не мог понять, как они устанавливали T
этого ...
Любая помощь будет высоко ценится, я, вероятно, смотрю на это неправильно!