我有一个类别列表(实体),每个类别都有父母。以下是该类别的模型:
public class Category { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int CategoryId { get; set; } public int? ParentId { get; set; } public string Name { get; set; } public virtual Category Parent { get; set; } }
我需要填充一个SelectList,这样父母就会先来,而孩子们会缩进像:
我必须使用此选择列表来编辑编辑和更新表单中的下拉列表。我该怎么做呢?客户端?服务器端?
感谢您提供的任何帮助。
答案 0 :(得分:3)
这让我想到在没有interface
的依赖的情况下实现它,我仍然认为这是合理的。这是使用扩展方法的替代解决方案,不需要实现interface
。
扩展方法
public static class ExtensionMethods
{
/// <summary>
/// Returns a single-selection select element containing the options specified in the items parameter.
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
/// <param name="helper">The class being extended.</param>
/// <param name="items">The collection of items used to populate the drop down list.</param>
/// <param name="parentItemsPredicate">A function to determine which elements are considered as parents.</param>
/// <param name="parentChildAssociationPredicate">A function to determine the children of a given parent.</param>
/// <param name="dataValueField">The value for the element.</param>
/// <param name="dataTextField">The display text for the value.</param>
/// <returns></returns>
public static MvcHtmlString DropDownGroupList<T>(
this HtmlHelper helper,
IEnumerable<T> items,
Func<T, bool> parentItemsPredicate,
Func<T, T, bool> parentChildAssociationPredicate,
string dataValueField,
string dataTextField)
{
var html = new StringBuilder("<select>");
foreach (var item in items.Where(parentItemsPredicate))
{
html.Append(string.Format("<optgroup label=\"{0}\">", item.GetType().GetProperty(dataTextField).GetValue(item, null)));
foreach (var child in items.Where(x => parentChildAssociationPredicate(x, item)))
{
var childType = child.GetType();
html.Append(string.Format("<option value=\"{0}\">{1}</option>", childType.GetProperty(dataValueField).GetValue(child, null), childType.GetProperty(dataTextField).GetValue(child, null)));
}
html.Append("</optgroup>");
}
html.Append("</select>");
return new MvcHtmlString(html.ToString());
}
}
根据您的Category
class
用法
当我写完这篇文章的时候,我不太确定这有什么价值,但我想我还是会发布它。 如您所见,您的 不要忘记添加必要的验证!@this.Html.DropDownGroupList(YourCollection, x => !x.ParentId.HasValue, (x, y) => { return x.ParentId.Equals(y.CategoryId); }, "CategoryId", "Name")
class
必须知道其父级的ID,并且子级和父级的显示名称应使用dataTextField
参数指示的相同属性。因此,基本上,您的class
需要属性:Id,ParentId和Name,您可以使用Func<T, bool>
和Func<T, T, bool>
参数来确定关系。
答案 1 :(得分:1)
我会在optgroup
语法中使用razor
这样做服务器端。
<select>
@foreach(var parent in categories.Where(x => !x.ParentId.HasValue)
{
<optgroup label="@parent.Name">
@foreach(var child in categories.Where(x => x.ParentId.Equals(parent.CategoryId))
{
<option value="@child.CategoryId">@child.Name</option>
}
</optgroup>
}
</select>
我还会将其作为扩展方法,因此它需要其他可用的HTML帮助程序方法。
修改强>
扩展方法可以接受实现如下简单界面的项集合:
public interface IGroupable
{
int Id { get; set; }
string Name { get; set; }
int? ParentId { get; set; }
}
public class Category : IGroupable
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CategoryId { get; set; }
public int? ParentId { get; set; } //implements IGroupable.ParentId
public string Name { get; set; } //implements IGroupable.Name
public virtual Category Parent { get; set; }
#region [IGroupable Specific Implementation]
public int Id { get { return this.CategoryId; } }
#endregion
}
public static class ExtensionMethods
{
public static MvcHtmlString DropDownGroupList(this HtmlHelper helper, IEnumerable<IGroupable> items)
{
var html = new StringBuilder("<select>");
foreach (var item in items.Where(x => !x.ParentId.HasValue))
{
html.Append(string.Format("<optgroup label=\"{0}\">", item.Name));
foreach(var child in items.Where(x => x.ParentId.Equals(item.Id)))
{
html.Append(string.Format("<option value=\"{0}\">{1}</option>", child.Id, child.Name));
}
html.Append("</optgroup>");
}
html.Append("</select>");
return new MvcHtmlString(html.ToString());
}
}