加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

使用Linq表达式在扩展方法中有趣(?)

发布时间:2020-12-16 03:47:42 所属栏目:asp.Net 来源:网络整理
导读:我写了一个 HtmlHelper表达式,我花了很多时间将标题标签放入我的下拉列表中,如下所示: public static HtmlString SelectForTModel,TProperty,TListItem( this HtmlHelperTModel htmlHelper,ExpressionFuncTModel,TProperty expression,IEnumerableTListItem
我写了一个 HtmlHelper表达式,我花了很多时间将标题标签放入我的下拉列表中,如下所示:

public static HtmlString SelectFor<TModel,TProperty,TListItem>(
        this HtmlHelper<TModel> htmlHelper,Expression<Func<TModel,TProperty>> expression,IEnumerable<TListItem> enumeratedItems,string idPropertyName,string displayPropertyName,string titlePropertyName,object htmlAttributes) where TModel : class
    {
        //initialize values
        var metaData = ModelMetadata.FromLambdaExpression(expression,htmlHelper.ViewData);
        var propertyName = metaData.PropertyName;
        var propertyValue = htmlHelper.ViewData.Eval(propertyName).ToStringOrEmpty();
        var enumeratedType = typeof(TListItem);

        //build the select tag
        var returnText = string.Format("<select id="{0}" name="{0}"",HttpUtility.HtmlEncode(propertyName));
        if (htmlAttributes != null)
        {
            foreach (var kvp in htmlAttributes.GetType().GetProperties()
             .ToDictionary(p => p.Name,p => p.GetValue(htmlAttributes,null)))
            {
                returnText += string.Format(" {0}="{1}"",HttpUtility.HtmlEncode(kvp.Key),HttpUtility.HtmlEncode(kvp.Value.ToStringOrEmpty()));
            }
        }
        returnText += ">n";

        //build the options tags
        foreach (TListItem listItem in enumeratedItems)
        {
            var idValue = enumeratedType.GetProperties()
             .FirstOrDefault(p => p.Name == idPropertyName)
             .GetValue(listItem,null).ToStringOrEmpty();
            var titleValue = enumeratedType.GetProperties()
             .FirstOrDefault(p => p.Name == titlePropertyName)
             .GetValue(listItem,null).ToStringOrEmpty();
            var displayValue = enumeratedType.GetProperties()
             .FirstOrDefault(p => p.Name == displayPropertyName)
             .GetValue(listItem,null).ToStringOrEmpty();
            returnText += string.Format("<option value="{0}" title="{1}"",HttpUtility.HtmlEncode(idValue),HttpUtility.HtmlEncode(titleValue));
            if (idValue == propertyValue)
            {
                returnText += " selected="selected"";
            }
            returnText += string.Format(">{0}</option>n",displayValue);
        }

        //close the select tag
        returnText += "</select>";
        return new HtmlString(returnText);
    }

……这很有效,但有时我想走得更远.我想自定义这个野兽的id,display和title piece,而不必写出html.例如,如果我在模型中有一些类,如下所示:

public class item
{
    public int itemId { get; set; }
    public string itemName { get; set; }
    public string itemDescription { get; set; }
}

public class model
{
    public IEnumerable<item> items { get; set; }
    public int itemId { get; set; }
}

在我看来,我可以写:

@Html.SelectFor(m => m.itemId,Model.items,"itemId","itemName","itemDescription",null)

…我会得到一个带有标题属性等的精彩下拉列表.只要枚举项具有与我想要显示它们完全相同的属性,这就很棒了.但我真正喜欢的是:

@Html.SelectFor(m => m.itemId,id=>id.itemId,disp=>disp.itemName,title=>title.itemName + " " + title.itemDescription,null)

…在这种情况下,选项上的title属性是itemName属性和itemDescription属性的串联.我承认lambda表达式的元级别,Linq函数让我有点头晕.有人能指出我正确的方向吗?

最终结果对于那些好奇的人,以下代码使我可以使用lambda表达式完全控制选择列表的ID,Title和DisplayText属性:

public static HtmlString SelectFor<TModel,TProperty>> forExpression,Attribute<TListItem> idExpression,Attribute<TListItem> displayExpression,Attribute<TListItem> titleExpression,object htmlAttributes,bool blankFirstLine) where TModel : class
    {
        //initialize values
        var metaData = ModelMetadata.FromLambdaExpression(forExpression,HttpUtility.HtmlEncode(kvp.Value.ToStringOrEmpty()));
            }
        }
        returnText += ">n";

        if (blankFirstLine)
        {
            returnText += "<option value=""></option>";
        }

        //build the options tags
        foreach (TListItem listItem in enumeratedItems)
        {
            var idValue = idExpression(listItem).ToStringOrEmpty();
            var displayValue = displayExpression(listItem).ToStringOrEmpty();
            var titleValue = titleExpression(listItem).ToStringOrEmpty();
            returnText += string.Format("<option value="{0}" title="{1}"",displayValue);
        }

        //close the select tag
        returnText += "</select>";
        return new HtmlString(returnText);
    }

    public delegate object Attribute<T>(T listItem);

解决方法

如果您不需要各个选项的title属性,您的代码可以简化为:

public static HtmlString SelectFor<TModel,TIdProperty,TDisplayProperty,TListItem>(
    this HtmlHelper<TModel> htmlHelper,Expression<Func<TListItem,TIdProperty>> idProperty,TDisplayProperty>> displayProperty,object htmlAttributes
) where TModel : class
{
    var id = (idProperty.Body as MemberExpression).Member.Name;
    var display = (displayProperty.Body as MemberExpression).Member.Name;
    var selectList = new SelectList(enumeratedItems,id,display);
    var attributes = new RouteValueDictionary(htmlAttributes);
    return htmlHelper.DropDownListFor(expression,selectList,attributes);
}

并像这样使用:

@Html.SelectFor(
    m => m.itemId,id => id.itemId,disp => disp.itemName,null
)

如果你需要title属性,那么你必须实现DropDownList帮助器手动完成的所有操作,这可能会非常麻烦.以下是所有功能的一小部分示例:

public static class HtmlExtensions
{
    private class MySelectListItem : SelectListItem
    {
        public string Title { get; set; }
    }

    public static HtmlString SelectFor<TModel,Func<TListItem,string> titleProperty,object htmlAttributes
    ) where TModel : class
    {
        var name = ExpressionHelper.GetExpressionText(expression);
        var fullHtmlName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);

        var select = new TagBuilder("select");
        var compiledDisplayProperty = displayProperty.Compile();
        var compiledIdProperty = idProperty.Compile();
        select.GenerateId(fullHtmlName);
        select.MergeAttributes(new RouteValueDictionary(htmlAttributes));
        select.Attributes["name"] = fullHtmlName;
        var selectedValue = htmlHelper.ViewData.Eval(fullHtmlName);
        var options = 
            from i in enumeratedItems
            select ListItemToOption(
                ItemToSelectItem(i,selectedValue,compiledIdProperty,compiledDisplayProperty,titleProperty)
            );
        select.InnerHtml = string.Join(Environment.NewLine,options);
        return new HtmlString(select.ToString(TagRenderMode.Normal));
    }

    private static MySelectListItem ItemToSelectItem<TListItem,TDisplayProperty>(TListItem i,object selectedValue,TIdProperty> idProperty,TDisplayProperty> displayProperty,string> titleProperty)
    {
        var value = Convert.ToString(idProperty(i));
        return new MySelectListItem
        {
            Value = value,Text = Convert.ToString(displayProperty(i)),Title = titleProperty(i),Selected = Convert.ToString(selectedValue) == value
        };
    }

    private static string ListItemToOption(MySelectListItem item)
    {
        var builder = new TagBuilder("option");
        builder.Attributes["value"] = item.Value;
        builder.Attributes["title"] = item.Title;
        builder.SetInnerText(item.Text);
        if (item.Selected)
        {
            builder.Attributes["selected"] = "selected";
        }
        return builder.ToString();
    }
}

然后像这样使用:

@Html.SelectFor(
    m => m.itemId,title => title.itemName + " " + title.itemDescription,null
)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读