我最近将一个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 ...)
非常感谢您在解决此问题时可以给予的任何帮助。
答案 0 :(得分:0)
也浪费了大约一个小时。在vb.net中,您需要将第一个参数htmlHelper传递给您的扩展方法。在C#中你不会。
@RequiredLabelFor(Me.Html,Function(x)x.EmployeeID)
Grrr vb.net!