I didn't like that the AddView template ignored the
DisplayAttribute(Order=0)
.
So I adjusted it following http://blogs.msdn.com/b/webdev/archive/2009/01/29/t4-templates-a-quick-start-guide-for-asp-net-mvc-developers.aspx
I added the following to my
CodeTemplates/AddView/CSHTML/List.tt
file
IEnumerable<PropertyInfo> SortProperties(IEnumerable<PropertyInfo> props)
{
var pl = props.ToList();
var length = pl.Count;
var q = from p in pl
let da = p.GetCustomAttribute<DisplayAttribute>()
where da != null
let o = da.GetOrder()
where o.HasValue
orderby o
select new { p, o.Value };
var ordered = q.ToList();
var remainder = pl.Except(ordered.Select(o => o.p).ToArray()).ToArray();
var destination = new PropertyInfo[length];
foreach (var o in ordered)
{
destination[o.Value] = o.p;
}
if (ordered.Count == length)
return ordered.Select(o => o.p).ToArray();
var remainderCount = 0;
for (int i = 0; i < pl.Count; i++)
{
if (destination[i] != null)
continue;
destination[i] = remainder[remainderCount];
remainderCount++;
}
return destination;
}
then updated
GetEligibleProperties
to call it in the property loop.
Here's the unit test:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace MyMvc.Tests.CodeTemplates.AddView.CSHTML
{
[TestClass]
public class ListTests
{
class SortTester
{
public Guid FileGuid { get; set; }
[Display(Order = 0)]
public string FileName { get; set; }
public int CustomerId { get; set; }
[Display(Order = 1)]
public int? ExpectedTrxCount { get; set; }
}
IEnumerable<PropertyInfo> SortProperties(IEnumerable<PropertyInfo> props)
{
var pl = props.ToList();
var length = pl.Count;
var q = from p in pl
let da = p.GetCustomAttribute<DisplayAttribute>()
where da != null
let o = da.GetOrder()
where o.HasValue
orderby o
select new { p, o.Value };
var ordered = q.ToList();
var remainder = pl.Except(ordered.Select(o => o.p).ToArray()).ToArray();
var destination = new PropertyInfo[length];
foreach (var o in ordered)
{
Console.WriteLine("ordering:" + o.p.Name);
destination[o.Value] = o.p;
}
if (ordered.Count == length)
return ordered.Select(o => o.p).ToArray();
var remainderCount = 0;
for (int i = 0; i < pl.Count; i++)
{
if (destination[i] != null)
continue;
destination[i] = remainder[remainderCount];
remainderCount++;
}
foreach (var d in destination) Console.WriteLine(d.Name);
return destination;
}
[TestMethod]
public void Sort_DisplayOne_IsSecond()
{
var type = typeof(SortTester);
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var expected = props.First(p => p.Name == LinqOp.PropertyOf(()=>new SortTester().FileName).Name);
var sorted = SortProperties(props);
var actual = sorted.First();
Assert.AreEqual(expected, actual);
}
[TestMethod]
public void Sort_DisplayZero_IsFirst()
{
var type = typeof(SortTester);
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var expected = props.First(p => p.Name == LinqOp.PropertyOf(() => new SortTester().ExpectedTrxCount).Name);
var sorted = SortProperties(props);
var actual = sorted.Skip(1).First();
Assert.AreEqual(expected, actual);
}
}
}
Here's the source of LinqOp
No comments:
Post a Comment