Несколько IEnumerable реализации в mvc3 на VIew

@{IEnumerable<BC.Models.APPLICATION> data = ViewBag.list;} 
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No").Filterable(true);
})

Но я хочу сделать что-то подобное:

@if(some conditon)
{
@{IEnumerable<BC.Models.APPLICATION> data = ViewBag.list;} 
}
else
{
@{IEnumerable<BC.Models.RIGHTS> data = ViewBag.list;} 
}
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No");
})

Но это не работает, может кто-нибудь иметь представление об этом.
Теперь, если я делаю что-то подобное, это работает

@if(some conditon)
    {
    @{IEnumerable<BC.Models.APPLICATION> data = ViewBag.list;} 
    @Html.Grid(data).Columns(columns =>
    {
    columns.Add(c => c.APPLICATION_NO).Titled("Application No");
    })
    }
    else
    {
    @{IEnumerable<BC.Models.RIGHTS> data = ViewBag.list;} 
    @Html.Grid(data).Columns(columns =>
    {
    columns.Add(c => c.APPLICATION_NO).Titled("Application No");
    })
    }

Моя проблема в том, что свойство APPLICATION_NO присутствует в обоих классах Model, поэтому я не хочу использовать

    @Html.Grid(data).Columns(columns =>
    {
    columns.Add(c => c.APPLICATION_NO).Titled("Application No");
    })

Дважды в моем коде.

3 ответа

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

Что касается вашего последнего комментария, то, что вы хотите использовать, - это модель представления, то есть класс, созданный специально для отправки данных в представление для его отображения.

Для этого:

  1. создать публичный класс, который имеет APPLICATION_NO (необходимо для класса модели представления)
  2. создайте другой открытый класс, который будет вашей моделью представления. Это класс, который формирует данные по мере необходимости в шаблоне бритвы (в этом случае он будет содержать список класса, определенного в 1)
  3. в вашем контроллере верните представление, передающее модель в качестве второго параметра. Т.е. не используйте ViewBag/ViewData, но модель представления вместо этого, как это return View("ViewName", model)
  4. используйте модель в своем представлении: объявите тип модели, используя @model и использовать его внутри шаблонов Razor с предоставленными Model переменная

Таким образом, вы формируете данные на сервере и избегаете включения большого количества кода в шаблон Razor (что не рекомендуется). И, конечно, у вас есть intellisense, и ваши шаблоны становятся напечатанными.

Код для 1:

public class ApplicationModel
{
   public int APPLICATION_NO {get; set;}
}

Код для 2:

public class ApplicationsViewModel
{
   public List<ApplicationModel> Applications { get; set; }
}

Код на 3 (внутри контроллера)

var model = new ApplicationsViewModel();

if (...) // include the condition to choose the kind of data inside the list
{
   model.Applications = list.Select(item =>
     new ApplicationModel { APPLICATION_NO = item.APPLICATION_NO } ).ToList()
}
else
{
   // same code here, for the other kind of data in the list
}

// return the view with this model
return View("ApplicationView", model);

Код для 4:

// decalre the model type at the beginning
@model YourNamespace.ApplicationViewModel;

// access the model using the Model variable
@Html.Grid(Model.Applications).Columns(columns =>
  {
  columns.Add(c => c.APPLICATION_NO).Titled("Application No");
  })

Это позволяет создавать приложения MVC с несколькими преимуществами, такими как тестируемость, повторное использование кода, читаемость или доступность ModelState, Поверьте мне, многие из этих вещей действительно, очень важны, особенно ModelState,

Кроме того, вы можете использовать аннотации кода (атрибуты, которые предоставляют дополнительную информацию помощникам HTML) в вашей модели представления, эти атрибуты могут обеспечивать метки, проверку и некоторые другие автоматические функции.

Не сомневайтесь, чтобы включить все необходимые свойства в вашу модель представления.

Использование модели представления позволяет вам создать специальный класс без необходимости изменять свой домен или классы бизнес-уровня, то есть вам не нужно использовать интерфейсы, аннотации кода и так далее. Однако часто интересно добавлять аннотации кода в бизнес-классы и вкладывать их в модели представлений.

Помните, что иногда вы можете использовать ту же модель представления для отправки данных обратно на сервер, указав их в качестве типа параметра вашего действия POST.

Кстати, интерфейсное решение хорошее, но это решение не требует интерфейса. (Это решение будет иметь лучшую реализацию с использованием этого интерфейса, но это ваш выбор).

@if(some conditon)
{
@{IEnumerable<BC.Models.APPLICATION> data = ViewBag.list;} 
}
else
{
@{IEnumerable<BC.Models.RIGHTS> data = ViewBag.list;} 
}
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No");
})

Код не может работать, потому что данные объявляются в блоки if. Если сетка должна работать только с общими полями двух классов, вы можете подумать об использовании интерфейса, который APPLICATION и RIGHTS реализуют и изменяют код следующим образом:

@{IEnumerable<BC.Models.IAPPLICATION_NO> data = (IEnumerable<BC.Models.IAPPLICATION_NO>)ViewBag.list;} 
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No");
})

где IAPPLICATION_NO - это интерфейс типа:

public interface IAPPLICATION_NO
{
    string APPLICATION_NO { get; }
}

Я не знаю, что такое APPLICATION_NO, поэтому я использовал строку, и интерфейс может определить только get для grid.

В противном случае, если вам нужно отобразить разные данные для этих двух типов, вам следует рассмотреть возможность использования двух представлений или другого объявления сетки в блоках if.

Я работал над образцом моего ответа на VS:

Я прилагаю вам код:

public interface AInterface
{
    string AProperty { get; }
}

public class AList : AInterface
{
    public string AProperty { get; set; }
}

public class BList : AInterface
{
    public string AProperty { get; set; }
}

это классы

Теперь контроллер:

public class TestController : Controller
{
    public ActionResult Index()
    {
        var random = new Random((int)DateTime.Now.Ticks);

        if (random.Next() % 2 == 0)
            ViewBag.List = new List<AList> { new AList { AProperty = "Atestvalue" } };
        else
            ViewBag.List = new List<BList> { new BList { AProperty = "Atestvalue" } };

        return View();
    }
}

и вид:

@{
    ViewBag.Title = "Index";
    IEnumerable<TestMvcApplication.Interfaces.AInterface> test = ViewBag.List;
}

<h2>Index</h2>

@foreach (var item in test)
{
    <div>
        @item.AProperty
    </div>
}

это решает вашу проблему, как вы можете видеть

Без использования интерфейсов:

@{IEnumerable<dynamic> data = (IEnumerable<dynamic>)ViewBag.list;} 
@Html.Grid(data).Columns(columns =>
{
columns.Add(c => c.APPLICATION_NO).Titled("Application No");
})

но вы теряете завершение IntelliSense, и если член отсутствует, я думаю, что вы получите ошибку во время выполнения.

Я попробовал вашу сборку Grid, но она использует выражение C# и несовместима с динамическим. Другим решением может быть приведение одного списка к другому с помощью LINQ в контроллере:

IEnumerable<BC.Models.Application> data;
if (some condition)
{
    data = applicationList; //applicationList's type is IEnumerable<BC.Models.Application>
}
else
{
    data = rightsList.Select(t => new Application { APPLICATION_NO = t.APPLICATION_NO }); //rightsList's type is IEnumerable<BC.Models.RIGHTS>
}

ViewBag.list = data;

В представлении вы можете сохранить рабочий код, который вы разместили в верхней части вопроса. У вас нет многотипной поддержки IEnumerable, потому что вы используете только один тип, но без использования общего интерфейса между этими классами, я думаю, что мы должны перейти к размышлению, но я думаю, что этот код сложно написать.

Почему бы и нет

@{string columnName = "default column name";
if(some_condition)
{
    // I'm not sure what's going on with the data variable
    columnName = "alternate column name";
}
else
{
    // Again, do your stuff with the data variable
}
}
@Html.Grid(data).Columns(columns =>
{
    columns.Add(c => c.APPLICATION_NO).Titled(columnName);
})

Я думаю, что вы в конечном итоге получите (в лучшем случае) запутанный код, если попытаетесь быть слишком умными в своих взглядах. Сетка для рендеринга IEnumerable<A> не подходит для рендеринга IEnumerable<B> если A:ISomeInterface а также B:ISomeInterface и сетка оказывает ISomeInterface, В качестве альтернативы просто передайте имя столбца как свойство модели представления.

Другие вопросы по тегам