public class FlatList { public FlatList(IEnumerable<string> columns, List<List<object>> data, int totalCount) { Columns = columns; Data = data; TotalCount = totalCount; } public IEnumerable<string> Columns { get; } public List<List<object>> Data { get; } public int TotalCount { get; } } public class ColumnMetaData<T> { public string Name { get; set; } public Func<T, object> ValueSelector { get; set; } } public class FlatListBuilder<T> { private readonly List<ColumnMetaData<T>> Columns = new(); public FlatListBuilder<T> AddColumn(string propertyName, Func<T, object> valueGetter) { var x = new ColumnMetaData<T>(); x.Name = propertyName; x.ValueSelector = (y) => { return valueGetter(y); }; Columns.Add(x); return this; } public FlatList Build(IEnumerable<T> items, int? totalCount = null) { var data = items.Select(x => Columns.Select(y => y.ValueSelector(x)).ToList()).ToList(); return new FlatList(Columns.Select(x => x.Name), data, totalCount ?? items.Count()); } } // usage: var flatListBuilder = new FlatListBuilder<VmLookupItem>() .AddColumn("id", x => x.Id) .AddColumn("name", x => x.Description) .AddColumn("additionalInfo", x => x.AdditionalInfo); return flatListBuilder.Build(cachedItems);
Convert data back in typescript:
export interface IListView { columns: string[]; data: Array<any[]>; } export function mapListView<T>(listView: IListView): T[] { const columns = listView.columns.map((name, i) => ({ index: i, name: name })); return listView.data.map((row) => { const item: any = {}; for (const { index, name } of columns) item[name] = row[index]; return item as T; }); } async getAllDebtorArticles(debtorId: string): Promise<IDebtorArticle[]> { const listView = await appDependencies.IRestApi.request(`api/article/debtor/${debtorId}`).getData<IListView>(); return mapListView<IDebtorArticle>(listView); }
744000cookie-checkC# ListView/FlatList Builder