#c_sharp #aspnet #list
Дело в том, что впервые столкнулся с моделью, где более 40 свойств, которые нужно
отобразить.
[Display(Name = "Название 1")]
public string Name1 { get; set; }
[Display(Name = "Название 2")]
public int Name2 { get; set; }
[Display(Name = "Название 3")]
public int Name3 { get; set; }
[Display(Name = "Название 4")]
public int Name4 { get; set; }
В представлении мне нужно отобразить данные в виде таблицы
@Html.LabelFor(c => common.Name1)
|
@Html.LabelFor(c => common.Name2)
|
@Html.LabelFor(c => common.Name3)
|
Мне кажется нелогичным такой способ вывода информации и подозреваю, что можно сделать
это более легким способом, который пока не смог найти... Подскажите, пожалуйста.
Есть ли что-либо похожее на это
@{
foreach(var DisplayName in Model.ObjectPropertyAttributies)
DisplayName |
}
Ответы
Ответ 1
Если по работе нужно создавать много однотипных файлов то можно в сторону кодогенерации
посмотреть: https://msdn.microsoft.com/en-us/library/bb126445.aspx
Я это использую, чтобы делать заготовки под view model:
<#@ template debug="true" hostSpecific="false" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core" #>
<#@ Assembly Name="$(SolutionDir)packages\Prism.Core.6.2.0\lib\net45\Prism.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="Prism.Mvvm" #>
<#
// This template generates the code for a ViewModel which is based on some model.
// Also supposed that used MVVM pattern and Prism Library
// Full name of type for which will be generated ViewModel
Type modelType = typeof(someType);
PopulateTypeNameProperties(modelType);
// Namecpase inside which the code of ViemModel will be put
string space = "Solution.ViewModel";
// Begining template's code
#>namespace <#= space#>
{
// usings
using <#= modelType.Namespace#>;
public class <#= modelType.Name #>ViewModel : BindableBase
{
#region Fields
<# foreach(var tuple in this.typeNameProperties)
{ #>
private <#= tuple.Item1 #> <#= tuple.Item3 #>;
<#}#>
#endregion
#region Property for binding
<# foreach(var tuple in this.typeNameProperties)
{ #>
public <#= tuple.Item1 #> <#= tuple.Item2 #>
{
get
{
return this.<#= tuple.Item3 #>;
}
set
{
this.SetProperty(ref this.<#= tuple.Item3 #>, value);
}
}
<#}#>
#endregion
public <#= modelType.Name #>ViewModel() {}
public <#= modelType.Name #>ViewModel(<#= modelType.Name #> model)
{
<# foreach(var tuple in this.typeNameProperties)
{ #>
this.<#= tuple.Item3 #> = model.<#= tuple.Item2 #>;
<#}#>}
public void UpdateViewModel(<#= modelType.Name #> model)
{
<# foreach(var tuple in this.typeNameProperties)
{ #>
this.<#= tuple.Item2 #> = model.<#= tuple.Item2 #>;
<#}#>}
public static explicit operator <#= modelType.Name #> (<#= modelType.Name
#>ViewModel viewModel)
{
<# int beforeLast = typeNameProperties.Count - 1; #>
return new <#= modelType.Name #>
{
<# for (int i = 0; i < beforeLast; ++i)
{ #>
<#= typeNameProperties[i].Item2 #> = viewModel.<#= typeNameProperties[i].Item3 #>,
<#}#><# if (typeNameProperties.Count > 1)
{
this.Write(string.Format("\t\t{0} = viewModel.{1}", typeNameProperties[beforeLast].Item2,
typeNameProperties[beforeLast].Item3));
}
this.Write("\r\n");
#>
};
}
}
}
<#
// Ending template's code
#>
<#+
// The storage for couple type - name of Properties
private List> typeNameProperties = new List>();
private void PopulateTypeNameProperties(Type modelType)
{
foreach (var p in modelType.GetProperties())
{
if (string.CompareOrdinal(p.Name, "ErrorMessage") == 0)
{
continue;
}
string type = GetShortTypeName(p.PropertyType.Name);
var name = p.Name;
char firstLetter = name[0];
var property = char.ToUpperInvariant(firstLetter).ToString() + name.Substring(1);
var field = char.ToLowerInvariant(firstLetter).ToString() + name.Substring(1);
typeNameProperties.Add(new Tuple(type, property, field));
}
}
#>
<#+
private string GetShortTypeName(string typeName)
{
switch(typeName)
{
case "Int32":
return "int";
/ .......
case "Object":
return "object";
default:
return typeName;
}
}
#>
Правда есть немного заморочек с отступами, и выглядит не очень читабельно. Но не
нужно тратить время на медитативный набор свойств view model. Результат вот такой:
namespace Solution.ViewModel
{
// usings
public class CurrencyInfoViewModel : BindableBase
{
#region Fields
private string name;
private string shortName;
private DateTime modifyTime;
private int id;
#endregion
#region Property for binding
public string Name
{
get
{
return this.name;
}
set
{
this.SetProperty(ref this.name, value);
}
}
public string ShortName
{
get
{
return this.shortName;
}
set
{
this.SetProperty(ref this.shortName, value);
}
}
public DateTime ModifyTime
{
get
{
return this.modifyTime;
}
set
{
this.SetProperty(ref this.modifyTime, value);
}
}
public int Id
{
get
{
return this.id;
}
set
{
this.SetProperty(ref this.id, value);
}
}
#endregion
public CurrencyInfoViewModel() {}
public CurrencyInfoViewModel(CurrencyInfo model)
{
this.name = model.Name;
this.shortName = model.ShortName;
this.modifyTime = model.ModifyTime;
this.id = model.Id;
}
public void UpdateViewModel(CurrencyInfo model)
{
this.Name = model.Name;
this.ShortName = model.ShortName;
this.ModifyTime = model.ModifyTime;
this.Id = model.Id;
}
public static explicit operator CurrencyInfo (CurrencyInfoViewModel viewModel)
{
return new CurrencyInfo
{
Name = viewModel.name,
ShortName = viewModel.shortName,
ModifyTime = viewModel.modifyTime,
Id = viewModel.id
};
}
}
}
Ответ 2
Ответ на вопрос после значительной правки.
Вероятно, можно написать код, который будет действовать через рефлексию и вытягивать
информацию о полях. (Не пробовал, поэтому не знаю, есть ли какие-то подводные камни
- но путь выглядит вполне рабочим). Рефлексия - штука небыстрая, поэтому вполне возможно,
что овчинка не стоит выделки, я лично не слышал, чтобы кто-то шёл таким путём.
Классический способ - это использование кодогенерации. Правый клик на папке контроллеров
в solution explorer, Add - Controller, шаблон "MVC Controller with views, using Entity
Framework" в котором укажите вашу модель, а студия вам сгенерирует полностью контроллер,
содержащий все CRUD методы, а также все необходимые view (и для создания-редактирования,
и для списка и для детального просмотра).
Ответ на предыдущую версию ответа:
Если вам дали утверждённый макет, в котором таблица на сорок строк - то как бы нелогичным
вам это не казалось - нужно взять и заверстать.
Либо вам нужно пойти к проектировщику интерфейса и объяснить ему, что сорок колонок
на экране мешают работать, а не помогают. Ну или не дизайнера переубеждать, а руководство.
Это правильное решение проблемы. Нужно начать прорабатывать пользовательские сценарии,
смотреть в каких какие колонки нужны. Возможно, что окажется, что и не нужно было столько
полей. Это - типичные проблемы энтерпрайза:
В моей практике был случай, когда удалось убедить руководство, что не нужно заставлять
вводить 96 полей, достаточно всего пяти.
Если же вам аналитики и руководство скажет, что тут только так нужно, чтобы на экране
был интерфейс чуть ли не гугл таблиц на экране с бесконечным количеством столбцов,
то есть ещё вариант, только они ни разу не простой.
Сделайте интерфейс, который позволяет скрывать/показывать столбцы.
Ответ 3
Если вам нужен просто цикл по всем свойствам - такой способ есть.
Для начала нужно получить метаданные вашей модели. Если это основная модель страницы,
то все просто - это ViewData.ModelMetadata.
Если же, судя по таблице, это элемент какой-нибудь коллекции, то получить его метаданные
проще через вызов new ViewDataDictionary<ТипЭлемента>(элемент).ModelMetadata. Точнее,
лучше сначала создать ViewDataDictionary вот так: var data = new ViewDataDictionary<ТипЭлемента>(),
а потом менять ему модель - это немного ускорит работу.
Ну а дальше все просто: у ModelMetadata есть все требуемые свойства:
@{
var data = new ViewDataDictionary<ТипЭлемента>(null);
@foreach (var propertyMetadata in data.ModelMetadata.Properties) {
@propertyMetadata.DisplayName; |
}
@foreach (var item in какаяТоКоллекция) {
data.Model = item;
@foreach (var propertyMetadata in data.ModelMetadata.Properties) {
@propertyMetadata.Model; |
}
}
}
Комментариев нет:
Отправить комментарий