In the process of getting this question this question answered, I realized I needed to separate my column-generation logic from the data population. This led to the need to preserve the ColumnDataBuilder<TDATA>
builder object that I used to create the columns, so that I could keep track of the type of my data.
In the process of getting this question answered, I realized I needed to separate my column-generation logic from the data population. This led to the need to preserve the ColumnDataBuilder<TDATA>
builder object that I used to create the columns, so that I could keep track of the type of my data.
In the process of getting this question answered, I realized I needed to separate my column-generation logic from the data population. This led to the need to preserve the ColumnDataBuilder<TDATA>
builder object that I used to create the columns, so that I could keep track of the type of my data.
Generic data for ListView
I'm in the midst of writing a custom ListView
for our application.
In the process of getting this question answered, I realized I needed to separate my column-generation logic from the data population. This led to the need to preserve the ColumnDataBuilder<TDATA>
builder object that I used to create the columns, so that I could keep track of the type of my data.
Ideally, usage will look something like this:
builder = MyListView.ColumnsFor<ReceiptHeaderForShipping>();
mlvShippingList.createColumns(_builder.Create("Receipt", 60, x => x.receiptNumber),
_builder.Create("Cust", 100, x => x.customer.LastName + ", " + x.customer.FirstName),
_builder.Create("Total", 60, MyListView.ColumnType.Currency, x => x.subTotal)
);
And then later
mlvShippingList.populateData(_builder, data);
In addition, the MyListView
will have to know what type of data it was built with, in order to know what type of ColumnDataBuilder
the IMyColumnData
comes from, so that it can cast to it in order to sort.
From MyListView
:
public partial class MyListView : ListView
{
public static ColumnDataBuilder<T> ColumnsFor<T>(IEnumerable<T> data)
{
return new ColumnDataBuilder<T>();
}
public void populateFromData<TDATA>(IEnumerable<TDATA> data, params ColumnDataBuilder<TDATA>.IMyListViewColumnData[] columns)
{
createColumns(columns);
populateData(data, columns);
}
public void createColumns<TDATA>(params ColumnDataBuilder<TDATA>.IMyListViewColumnData[] columns)
{
Columns.Clear();
foreach (var col in columns)
{
var ch = new ColumnHeader
{
Text = col.Name,
Width = col.Width,
Tag = col,
};
// Other formatting goes here
this.Columns.Add(ch);
}
}
private void populateData<TDATA>(IEnumerable<TDATA> data, params ColumnDataBuilder<TDATA>.IMyListViewColumnData[] columns)
{
Items.Clear();
var parsedData = data.Select(row => CreateListViewItem(columns, row));
this.Items.AddRange(parsedData.ToArray());
}
public class ColumnDataBuilder<T>
{
internal List<IMyListViewColumnData> columns = new List<IMyListViewColumnData>();
public interface IMyListViewColumnData
{
string Name { get; }
int Width { get; }
ColumnType Type { get; }
string GetDataString(T dataRow);
}
public delegate TOut FormatData<out TOut>(T dataIn);
public class MyListViewColumnData<TOut> : IMyListViewColumnData
{
public string Name { get; private set; }
public int Width { get; private set; }
public ColumnType Type { get; private set; }
private readonly FormatData<TOut> _dataFormatter;
public MyListViewColumnData(string name, int width, ColumnType type, FormatData<TOut> dataFormater)
{
_dataFormatter = dataFormater;
Type = type;
Width = width;
Name = name;
}
public string GetDataString(T dataRow)
{
object data = _dataFormatter(dataRow);
switch (Type)
{
case ColumnType.String:
case ColumnType.Integer:
case ColumnType.Decimal:
return data.ToString();
case ColumnType.Date:
return ((DateTime)data).ToShortDateString();
case ColumnType.Currency:
return ((decimal)data).ToString("c");
case ColumnType.Boolean:
return (bool)data ? "Y" : "N";
default:
throw new ArgumentOutOfRangeException();
}
}
}
#region Factory Methods
public IMyListViewColumnData Create<TOut>(string name, int width, ColumnType type, FormatData<TOut> dataFormater)
{
var col = new MyListViewColumnData<TOut>(name, width, type, dataFormater);
columns.Add(col);
return col;
}
public IMyListViewColumnData Create(string name, int width, FormatData<DateTime> dataFormater)
{
return Create(name, width, ColumnType.Date, dataFormater);
}
// More type-specific factories go here
#endregion
}
}
Am I totally off base at this point? Is this a reasonable track to go down?