C#到VB.Net HtmlHelper扩展转换错误

时间:2014-05-22 21:58:12

标签: vb.net

我最近将一个HtmlHelper从C#转换为VB.Net,我的剃刀视图中出现错误。出于某种原因,辅助方法是在视图中请求htmlhelper参数。我在C#中测试了原始代码并且它可以工作,并且它不需要第一个参数。这是代码:

原创C#扩展程序:

namespace MyNamespace
{
    public class ExtendedSelectListItem : SelectListItem
    {
        public object htmlAttributes { get; set; }
    }

    public static partial class HtmlHelperExtensions
    {
        static object GetModelStateValue(HtmlHelper htmlHelper, string key, Type destinationType)
        {
            ModelState modelState;
            if (htmlHelper.ViewData.ModelState.TryGetValue(key, out modelState))
            {
                if (modelState.Value != null)
                {
                    return modelState.Value.ConvertTo(destinationType, null /* culture */);
                }
            }
            return null;
        }

        public static MvcHtmlString ExtendedDropDownListFor<TModel, TProperty>(
            this HtmlHelper<TModel> htmlHelper,
            Expression<Func<TModel, TProperty>> expression,
            IEnumerable<ExtendedSelectListItem> selectList,
            string optionLabel,
            object htmlAttributes,
            object selectedValue)
        {
            return SelectInternal(
                htmlHelper,
                optionLabel,
                ExpressionHelper.GetExpressionText(expression),
                selectList,
                false /* allowMultiple */,
                HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes),
                selectedValue);
        }

        private static MvcHtmlString SelectInternal(
            this HtmlHelper htmlHelper,
            string optionLabel,
            string name,
            IEnumerable<ExtendedSelectListItem> selectList,
            bool allowMultiple,
            IDictionary<string, object> htmlAttributes,
            object selectedValue)
        {
            string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
            if (String.IsNullOrEmpty(fullName))
                throw new ArgumentException("No name");

            if (selectList == null)
                throw new ArgumentException("No selectlist");

            object defaultValue = (allowMultiple) ? GetModelStateValue(htmlHelper, fullName, typeof(string[])) : GetModelStateValue(htmlHelper, fullName, typeof(string));

            // If we haven't already used ViewData to get the entire list of items then we need to
            // use the ViewData-supplied value before using the parameter-supplied value.
            if (defaultValue == null)
                defaultValue = htmlHelper.ViewData.Eval(fullName);

            // If we still don't have the value, use what was passed in
            if (defaultValue == null)
                defaultValue = selectedValue;

            if (defaultValue != null)
            {
                IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue };
                IEnumerable<string> values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture);
                HashSet<string> selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase);
                List<ExtendedSelectListItem> newSelectList = new List<ExtendedSelectListItem>();

                foreach (ExtendedSelectListItem item in selectList)
                {
                    item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text);
                    newSelectList.Add(item);
                }
                selectList = newSelectList;
            }
            else
            {
                selectList.Where(li => li.Selected).ToList().ForEach(li => li.Selected = false);
            }

            // Convert each ListItem to an <option> tag
            StringBuilder listItemBuilder = new StringBuilder();

            // Make optionLabel the first item that gets rendered.
            if (optionLabel != null)
                listItemBuilder.Append(ListItemToOption(new ExtendedSelectListItem() { Text = optionLabel, Value = String.Empty, Selected = false }));

            foreach (ExtendedSelectListItem item in selectList)
            {
                listItemBuilder.Append(ListItemToOption(item));
            }

            TagBuilder tagBuilder = new TagBuilder("select")
            {
                InnerHtml = listItemBuilder.ToString()
            };
            tagBuilder.MergeAttributes(htmlAttributes);
            tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
            tagBuilder.GenerateId(fullName);
            if (allowMultiple)
                tagBuilder.MergeAttribute("multiple", "multiple");

            // If there are any errors for a named field, we add the css attribute.
            ModelState modelState;
            if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState))
            {
                if (modelState.Errors.Count > 0)
                {
                    tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
                }
            }

            tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name));

            return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
        }

        internal static string ListItemToOption(ExtendedSelectListItem item)
        {
            TagBuilder builder = new TagBuilder("option")
            {
                InnerHtml = HttpUtility.HtmlEncode(item.Text)
            };
            if (item.Value != null)
            {
                builder.Attributes["value"] = item.Value;
            }
            if (item.Selected)
            {
                builder.Attributes["selected"] = "selected";
            }
            builder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(item.htmlAttributes));
            return builder.ToString(TagRenderMode.Normal);
        }
    }

}

原始代码链接:Adding html class tag under <option> in Html.DropDownList

VB.Net扩展:

Namespace MyNamespace

    Public Module HtmlHelperExtensions
        Sub New()
        End Sub

        <System.Runtime.CompilerServices.Extension()> _
        Public Function ExtendedDropDownListFor(Of TModel, TProperty)(htmlHelper As HtmlHelper, expression As Expression(Of Func(Of TModel, TProperty)), selectList As IEnumerable(Of ExtendedSelectListItem), optionLabel As String, htmlAttributes As Object, selectedValue As Object) As MvcHtmlString
            ' allowMultiple 
            Return SelectInternal(htmlHelper, optionLabel, ExpressionHelper.GetExpressionText(expression), selectList, False, htmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), selectedValue)
        End Function

        <System.Runtime.CompilerServices.Extension()> _
        Private Function SelectInternal(htmlHelper As HtmlHelper, optionLabel As String, name As String, selectList As IEnumerable(Of ExtendedSelectListItem), allowMultiple As Boolean, htmlAttributes As IDictionary(Of String, Object), selectedValue As Object) As MvcHtmlString
            Dim fullName As String = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name)
            If [String].IsNullOrEmpty(fullName) Then
                Throw New ArgumentException("No name")
            End If

            If selectList Is Nothing Then
                Throw New ArgumentException("No selectlist")
            End If

            Dim defaultValue As Object = If((allowMultiple), GetModelStateValue(htmlHelper, fullName, GetType(String())), GetModelStateValue(htmlHelper, fullName, GetType(String)))

            ' If we haven't already used ViewData to get the entire list of items then we need to
            ' use the ViewData-supplied value before using the parameter-supplied value.
            If defaultValue Is Nothing Then
                defaultValue = htmlHelper.ViewData.Eval(fullName)
            End If

            ' If we still don't have the value, use what was passed in
            If defaultValue Is Nothing Then
                defaultValue = selectedValue
            End If

            If defaultValue IsNot Nothing Then
                Dim defaultValues As IEnumerable = If((allowMultiple), TryCast(defaultValue, IEnumerable), New Object() {defaultValue})
                Dim values As IEnumerable(Of String) = From value In defaultValues Select Convert.ToString(value, CultureInfo.CurrentCulture)
                Dim selectedValues As New HashSet(Of String)(values, StringComparer.OrdinalIgnoreCase)
                Dim newSelectList As New List(Of ExtendedSelectListItem)()

                For Each item As ExtendedSelectListItem In selectList
                    item.Selected = If((item.Value IsNot Nothing), selectedValues.Contains(item.Value), selectedValues.Contains(item.Text))
                    newSelectList.Add(item)
                Next
                selectList = newSelectList
            Else
                selectList.Where(Function(li) li.Selected).ToList().ForEach(Function(li) InlineAssignHelper(li.Selected, False))
            End If

            ' Convert each ListItem to an <option> tag
            Dim listItemBuilder As New StringBuilder()

            ' Make optionLabel the first item that gets rendered.
            If optionLabel IsNot Nothing Then
                listItemBuilder.Append(ListItemToOption(New ExtendedSelectListItem() With { _
                 .Text = optionLabel, _
                 .Value = [String].Empty, _
                 .Selected = False _
                }))
            End If

            For Each item As ExtendedSelectListItem In selectList
                listItemBuilder.Append(ListItemToOption(item))
            Next

            Dim tagBuilder As New TagBuilder("select") With { _
             .InnerHtml = listItemBuilder.ToString() _
            }
            tagBuilder.MergeAttributes(htmlAttributes)
            ' replaceExisting 
            tagBuilder.MergeAttribute("name", fullName, True)
            tagBuilder.GenerateId(fullName)
            If allowMultiple Then
                tagBuilder.MergeAttribute("multiple", "multiple")
            End If

            ' If there are any errors for a named field, we add the css attribute.
            Dim modelState As ModelState = New ModelState()
            If htmlHelper.ViewData.ModelState.TryGetValue(fullName, modelState) Then
                If modelState.Errors.Count > 0 Then
                    tagBuilder.AddCssClass(htmlHelper.ValidationInputCssClassName)
                End If
            End If

            tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name))

            Return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal))
        End Function

        Friend Function GetModelStateValue(htmlHelper As HtmlHelper, key As String, destinationType As Type) As Object
            Dim modelState As ModelState = New ModelState()
            If htmlHelper.ViewData.ModelState.TryGetValue(key, modelState) Then
                If modelState.Value IsNot Nothing Then
                    ' culture 
                    Return modelState.Value.ConvertTo(destinationType, Nothing)
                End If
            End If
            Return Nothing
        End Function

        Friend Function ListItemToOption(item As ExtendedSelectListItem) As String
            Dim builder As New TagBuilder("option") With { _
             .InnerHtml = HttpUtility.HtmlEncode(item.Text) _
            }
            If item.Value IsNot Nothing Then
                builder.Attributes("value") = item.Value
            End If
            If item.Selected Then
                builder.Attributes("selected") = "selected"
            End If
            builder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(item.htmlAttributes))
            Return builder.ToString(TagRenderMode.Normal)
        End Function
        Private Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
            target = value
            Return value
        End Function


    End Module

End Namespace

C#Razor查看语法:

@Html.ExtendedDropDownListFor(p => p.filter1.propName, (IEnumerable<ExtendedSelectListItem>)ViewBag.propNames, "", new { @class = "filter1" },null)

VB.Net Razor查看语法错误:

@Imports MyNamespace

@HtmlHelperExtensions.ExtendedDropDownListFor(Function(p) p.filter5.propName, CType(ViewBag.propNames, IEnumerable(Of ExtendedSelectListItem)), "", New With {.class = "filter5"}, Nothing)

由于扩展方法需要HtmlHelper参数,因此出现以下错误:

  
    

未为参数&quot; selectedValue&#39;指定参数&#39;公共函数ExtendedDropDownListFor ...)

  

非常感谢您在解决此问题时可以给予的任何帮助。

1 个答案:

答案 0 :(得分:0)

也浪费了大约一个小时。在vb.net中,您需要将第一个参数htmlHelper传递给您的扩展方法。在C#中你不会。

@RequiredLabelFor(Me.Html,Function(x)x.EmployeeID)

Grrr vb.net!