C# ListView Builder

Date: 2023-02-23
public class ListView
{
    public ListView(List<string> columns, List<List<object>> data)
    {
        Columns = columns;
        Data = data;
    }
    public List<string> Columns { get; }
    public List<List<object>> Data { get; }
}

public class ListViewBuilder<T>
{
    public class ListViewBuilderColumn
    {
        public ListViewBuilderColumn(string name, Func<T, object> valueSelector)
        {
            Name = name;
            ValueSelector = valueSelector;
        }
        public string Name { get; }
        public Func<T, object> ValueSelector { get; }
    }
    private readonly List<ListViewBuilderColumn> Columns = new();
    public ListViewBuilder<T> AddColumn(string columnName, Func<T, object> valueSelector)
    {
        Columns.Add(new ListViewBuilderColumn(columnName, valueSelector));
        return this;
    }

    public ListView Build(IEnumerable<T> items)
    {
        var columns = Columns.Select(x => x.Name).ToList();
        var data = items.Select(x => Columns.Select(y => y.ValueSelector(x)).ToList()).ToList();
        return new ListView(columns, data);
    }
}

// Example usage:
return new ListViewBuilder<BasicDebtorArticle>()
    .AddColumn("ArticleId", x => x.ArticleId)
    .AddColumn("DebtorId", x => x.DebtorId)
    .AddColumn("DebtorArticleId", x => x.DebtorArticleId)
    .AddColumn("ArticleDescription", x => x.ArticleDescription)
    .Build(articles);

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);
}

74400cookie-checkC# ListView Builder