HTMLhelper на основе бритвы MVC3 с выражениями поля лямбда на основе модели

Я создаю свободный HtmlHelper в MVC, чтобы создать сетку на основе HTML. Я знаю о mvc contrib и WebGrid, но я делаю свой собственный и имею конкретную проблему:

Я должен ввести это:

@Html.DSGridFor().AddColumn(x=>x.FirstOrDefault().Message)

но я хочу иметь возможность ввести это:

@Html.DSGridFor().AddColumn(x=>x.Message)

Код, который вызывается, когда я начинаю с @Html.DSGridFor(), принимает модель на основе страницы.

public static DSGridHelper<TModel> DSGridFor<TModel>(this HtmlHelper<TModel> html)
{
   return new DSGridHelper<TModel>(html);
}

а затем в классе DSGridHelper у меня есть это:

public DSGridHelper<TModel> AddColumn(Expression<Func<TModel, dynamic>> property, string HeaderText = null)
        {
            string ColumnName = (property.Body as MemberExpression).Member.Name;

            DSGridColumn DSGC = new DSGridColumn();
            DSGC.ColumnName = ColumnName;
            DSGC.HeaderText = HeaderText ?? ColumnName;
            DSColumnList.Add(DSGC);

            return this;
        }

public List<DSGridColumn> DSColumnList { get; set; }

и класс столбца на данный момент действительно базовый:

  public class DSGridColumn
    {
        public DSGridColumn()
        {

        }

        public string ColumnName { get; set; }
        public string HeaderText { get; set; }

    }

Я могу заставить этот код нормально работать со строковыми именами столбцов, но я хочу, чтобы код объявления на странице бритвы был простым по формату и строго типизированным. На данный момент мне нужно ввести x=>x.First().Message, но мне действительно нужно только x=>x.Message для идентификации столбца.

Я ценю любую помощь.

ОБНОВЛЕНИЕ

Благодаря Джастину теперь я могу предоставить свой/наш код.

Вид:

@(Html.DSGridFor3().AddColumn(x => x.Message)
                   .AddColumn(x => x.Host)
                   .ToMvcString())

Вызов помощника HTML:

public static DSGridHelper3<T> DSGridFor3<T>(this HtmlHelper<IEnumerable<T>> htmlHelper)
{
         return new DSGridHelper3<T>(htmlHelper);
}

Возвращаемый класс:

public class DSGridHelper3<T>
    {
        private HtmlHelper _htmlHelper;
        //private IEnumerable<T> _dataList;
        public List<DSGridColumn> DSColumnList { get; set; }

        public DSGridHelper3(HtmlHelper<IEnumerable<T>> htmlHelper)
        {
            _htmlHelper = htmlHelper;
           // _dataList = htmlHelper.ViewData.Model;
            DSColumnList = new List<DSGridColumn>();
        }

        public DSGridHelper3<T> AddColumn(Expression<Func<T, object>> property)
        {
            string columnName = (property.Body as MemberExpression).Member.Name;
            DSGridColumn DSGC = new DSGridColumn();
            DSGC.ColumnName = columnName;
            DSGC.HeaderText = columnName;
            DSColumnList.Add(DSGC);

            return this;
        }

        public MvcHtmlString ToMvcString()
        {
            sb.Append("<table>");
            sb.Append("<tr>");
            sb.Append("<td>");
            sb.Append("hello world within a table");
            sb.Append(@"</td>");
            sb.Append("<td>");
            sb.Append("hello world within a table");
            sb.Append(@"</td>");
            sb.Append(@"</tr>");
            sb.Append(@"</table>");


            return new MvcHtmlString(sb.ToString());

        }
    }

ОБНОВЛЕНИЕ 2

Если вы хотите вручную вставить другой тип (возможно, потому что вы собираетесь получить небольшое количество табличных данных из ViewData, а не из модели страницы), то вот еще немного кода:

Вид:

@(Html.DSGridFor3<DanSoftware.MVC.Areas.Errors.Code.ELMAH_Error>().AddColumn(x => x.Message).ToMvcString();)

Альтернативная подпись для DSGridHelper ... helper

public static DSGridHelper3<T> DSGridFor3<T>(this HtmlHelper htmlHelper)
        {
            return new DSGridHelper3<T>(htmlHelper);
        }

Дополнительный конструктор:

public DSGridHelper3(HtmlHelper htmlHelper)
        {
            _htmlHelper = htmlHelper;
            // _dataList = htmlHelper.ViewData.Model;
            DSColumnList = new List<DSGridColumn>();
        }

Надеюсь, это кому-то поможет, и спасибо, Джастин!


person Dan B    schedule 05.06.2011    source источник
comment
Но будьте осторожны — будьте осторожны с извлечением имени столбца — это не всегда работает. База данных в основном представляет собой таблицу Elmah. При попытке получить ErrorID выражение на самом деле имеет вид {x => Convert(x.ErrorId)}, что не работает в приведенном выше коде. РЕШЕНИЕ ДОБРО ПОЖАЛОВАТЬ В ЭТО ТОЖЕ!   -  person Dan B    schedule 07.06.2011
comment
Здесь открылся отдельный вопрос stackoverflow.com/questions /6269822/   -  person Dan B    schedule 07.06.2011


Ответы (1)


У меня нет с собой Visual Studio, но я попробую...

Я бы взял коллекцию в качестве типа данных либо в вашем методе DsGridFor, либо в методе AddColumn. Это позволит вам отправлять строго типизированные аргументы из коллекции. Допустим, вам нужен общий метод AddColumn для данной коллекции с доступом к свойствам класса и методам коллекции, он будет выглядеть примерно так (просто пример):

    public static DSGridHelper<T> AddColumn<T>(this HtmlHelper<IEnumerable<T>> htmlHelper, Expression<Func<T, object>> property) where T : class
    {
        string columnName = (property.Body as MemberExpression).Member.Name;

        DSGridColumn DSGC = new DSGridColumn();
        DSGC.ColumnName = ColumnName;
        DSGC.HeaderText = HeaderText ?? ColumnName;
        DSColumnList.Add(DSGC);

        return this;
    }

В вашей ситуации, чтобы создать новый класс DsGridHelper, я мог бы сначала явно установить тип модели, а затем добавить перегрузки по ходу дела:

    public static DSGridHelper<T> DSGridFor<T>(this HtmlHelper<IEnumerable<T>> htmlHelper) where T : class
    {
        return new DSGridHelper<T>(htmlHelper);
    }

И тогда мой DsGridHelper может выглядеть примерно так:

public class DsGridHelper<T>
{
    private HtmlHelper _htmlHelper;
    private IEnumerable<T> _dataList;

    public DsGridHelper(HtmlHelper<IEnumerable<T>> htmlHelper)
    {
        _htmlHelper = htmlHelper;
        _dataList = htmlHelper.ViewData.Model;
    }

    public DsGridHelper<T> AddColumn(Expression<Func<T, object>> property)
    {
        string columnName = (property.Body as MemberExpression).Member.Name;
        DSGridColumn DSGC = new DSGridColumn();
        DSGC.ColumnName = ColumnName;
        DSGC.HeaderText = HeaderText ?? ColumnName;
        DSColumnList.Add(DSGC);

        return this;
    }
}
person Justin Soliz    schedule 05.06.2011
comment
Код в основном работает (SUPER) с точки зрения IntelliSense, но при его запуске возникает ошибка: элемент модели, переданный в словарь, имеет тип «System.Data.Objects.ObjectQuery1[System.String]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1». - person Dan B; 07.06.2011
comment
Я предполагаю, что это где-то в вашем классе сетки, может быть, когда вы добавляете свои столбцы? Мне нужно увидеть немного больше вашего кода, чтобы понять, что вызывает проблему. - person Justin Soliz; 07.06.2011
comment
УСПЕХ! Я делал что-то очень глупое LOL. Это помогает, если передать правильный тип модели в представление. краснеть. Я опубликую свой код через секунду. Кстати - ты гений! - person Dan B; 07.06.2011
comment
Выглядит хорошо, рад, что смог помочь. Я посмотрю на вашу проблему с Elmah. - person Justin Soliz; 07.06.2011
comment
Еще один вопрос, о котором я только что подумал, - как мне лучше передать другую модель в реализацию, с которой вы мне помогли? У меня может быть две таблицы (возможно, меньшего размера), которые я добавляю на страницу, используя ViewData, а не модель. Еще раз спасибо Джастин! - person Dan B; 07.06.2011
comment
Ха-ха - разобрался с этим (не в elmah - приведение другого типа вручную) - обновленный вопрос. - person Dan B; 07.06.2011