+
@helper PropertyListItem(ModelMetadata property)
{
var propertyName = property.PropertyName;
diff --git a/samples/MvcSample.Web/Views/Shared/HelloWorldPartial.cshtml b/samples/MvcSample.Web/Views/Shared/HelloWorldPartial.cshtml
index e211035aab..b3caac0643 100644
--- a/samples/MvcSample.Web/Views/Shared/HelloWorldPartial.cshtml
+++ b/samples/MvcSample.Web/Views/Shared/HelloWorldPartial.cshtml
@@ -3,4 +3,4 @@
Hello @Model.Name from Partial
-Edit Something!
\ No newline at end of file
+Create Something!
\ No newline at end of file
diff --git a/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj b/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj
index db0cce19de..8b94db3a49 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj
+++ b/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj
@@ -141,6 +141,7 @@
+
@@ -156,7 +157,11 @@
+
+
+
+
diff --git a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs
index 64f9b102d9..f6b97780d3 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs
@@ -426,6 +426,54 @@ namespace Microsoft.AspNet.Mvc.Core
return GetString("HtmlHelper_NotContextualized");
}
+ ///
+ /// There is no ViewData item of type '{0}' that has the key '{1}'.
+ ///
+ internal static string HtmlHelper_MissingSelectData
+ {
+ get { return GetString("HtmlHelper_MissingSelectData"); }
+ }
+
+ ///
+ /// There is no ViewData item of type '{0}' that has the key '{1}'.
+ ///
+ internal static string FormatHtmlHelper_MissingSelectData(object p0, object p1)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("HtmlHelper_MissingSelectData"), p0, p1);
+ }
+
+ ///
+ /// The parameter '{0}' must evaluate to an IEnumerable when multiple selection is allowed.
+ ///
+ internal static string HtmlHelper_SelectExpressionNotEnumerable
+ {
+ get { return GetString("HtmlHelper_SelectExpressionNotEnumerable"); }
+ }
+
+ ///
+ /// The parameter '{0}' must evaluate to an IEnumerable when multiple selection is allowed.
+ ///
+ internal static string FormatHtmlHelper_SelectExpressionNotEnumerable(object p0)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("HtmlHelper_SelectExpressionNotEnumerable"), p0);
+ }
+
+ ///
+ /// The ViewData item that has the key '{0}' is of type '{1}' but must be of type '{2}'.
+ ///
+ internal static string HtmlHelper_WrongSelectDataType
+ {
+ get { return GetString("HtmlHelper_WrongSelectDataType"); }
+ }
+
+ ///
+ /// The ViewData item that has the key '{0}' is of type '{1}' but must be of type '{2}'.
+ ///
+ internal static string FormatHtmlHelper_WrongSelectDataType(object p0, object p1, object p2)
+ {
+ return string.Format(CultureInfo.CurrentCulture, GetString("HtmlHelper_WrongSelectDataType"), p0, p1, p2);
+ }
+
///
/// Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
///
diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Expressions/ViewDataEvaluator.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Expressions/ViewDataEvaluator.cs
index ff772a6335..abc9f250b5 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Expressions/ViewDataEvaluator.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Expressions/ViewDataEvaluator.cs
@@ -20,6 +20,12 @@ namespace Microsoft.AspNet.Mvc.Rendering.Expressions
return EvalComplexExpression(viewData, expression);
}
+ public static ViewDataInfo Eval(object indexableObject, [NotNull] string expression)
+ {
+ // Run through same cases as other Eval() overload but allow a null container.
+ return (indexableObject == null) ? null : EvalComplexExpression(indexableObject, expression);
+ }
+
private static ViewDataInfo EvalComplexExpression(object indexableObject, string expression)
{
foreach (var expressionPair in GetRightToLeftExpressions(expression))
diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs
index 6b8781ef33..72f3938a12 100644
--- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs
+++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs
@@ -1,10 +1,11 @@
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Net;
-using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Core;
@@ -224,6 +225,17 @@ namespace Microsoft.AspNet.Mvc.Rendering
additionalViewData);
}
+ public HtmlString DropDownList(string name, IEnumerable selectList, string optionLabel,
+ object htmlAttributes)
+ {
+ return GenerateDropDown(
+ metadata: null,
+ expression: name,
+ selectList: selectList,
+ optionLabel: optionLabel,
+ htmlAttributes: htmlAttributes);
+ }
+
public HtmlString Hidden(string name, object value, object htmlAttributes)
{
return GenerateHidden(metadata: null, name: name, value: value, useViewData: (value == null),
@@ -304,6 +316,16 @@ namespace Microsoft.AspNet.Mvc.Rendering
htmlAttributes: htmlAttributes);
}
+ public HtmlString Raw(string value)
+ {
+ return new HtmlString(value);
+ }
+
+ public HtmlString Raw(object value)
+ {
+ return new HtmlString(value == null ? null : value.ToString());
+ }
+
public virtual HtmlString ValidationSummary(bool excludePropertyErrors, string message, IDictionary htmlAttributes)
{
var formContext = ViewContext.ClientValidationEnabled ? ViewContext.FormContext : null;
@@ -522,6 +544,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
htmlAttributes: htmlAttributeDictionary);
}
+ protected HtmlString GenerateDropDown(ModelMetadata metadata, string expression,
+ IEnumerable selectList, string optionLabel, object htmlAttributes)
+ {
+ return GenerateSelect(metadata, optionLabel, expression, selectList, allowMultiple: false,
+ htmlAttributes: htmlAttributes);
+ }
+
///
/// Writes an opening
- /// The type of the model.
/// The type of the value.
/// An expression that identifies the object that contains the properties to display.
/// The name of the template that is used to render the object.
@@ -175,6 +174,43 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// The HTML markup for each property in the model.
HtmlString DisplayForModel(string templateName, string htmlFieldName, object additionalViewData);
+ ///
+ /// Returns a single-selection HTML {select} element using the specified name of the form field,
+ /// list items, option label, and HTML attributes.
+ ///
+ /// The name of the form field to return.
+ /// A collection of objects that are used to populate the
+ /// drop-down list.
+ /// The text for a default empty item. This parameter can be null.
+ /// An object that contains the HTML attributes to set for the {select} element.
+ /// Alternatively, an instance containing the HTML attributes.
+ ///
+ /// An HTML {select} element with an {option} subelement for each item in the list.
+ HtmlString DropDownList(
+ string name,
+ IEnumerable selectList,
+ string optionLabel,
+ object htmlAttributes);
+
+ ///
+ /// Returns a single-selection HTML {select} element for the object that is represented
+ /// by the specified expression using the specified list items, option label, and HTML attributes.
+ ///
+ /// The type of the value.
+ /// An expression that identifies the value to display.
+ /// A collection of objects that are used to populate the
+ /// drop-down list.
+ /// The text for a default empty item. This parameter can be null.
+ /// An object that contains the HTML attributes to set for the {select} element.
+ /// Alternatively, an instance containing the HTML attributes.
+ ///
+ /// An HTML {select} element with an {option} subelement for each item in the list.
+ HtmlString DropDownListFor(
+ [NotNull] Expression> expression,
+ IEnumerable selectList,
+ string optionLabel,
+ object htmlAttributes);
+
///
/// Converts the value of the specified object to an HTML-encoded string.
///
diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/MultiSelectList.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/MultiSelectList.cs
new file mode 100644
index 0000000000..ed39386d51
--- /dev/null
+++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/MultiSelectList.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using Microsoft.AspNet.Mvc.Rendering.Expressions;
+
+namespace Microsoft.AspNet.Mvc.Rendering
+{
+ public class MultiSelectList : IEnumerable
+ {
+ private IList _groups;
+
+ public MultiSelectList([NotNull] IEnumerable items)
+ : this(items, selectedValues: null)
+ {
+ }
+
+ public MultiSelectList([NotNull] IEnumerable items, IEnumerable selectedValues)
+ : this(items, dataValueField: null, dataTextField: null, selectedValues: selectedValues)
+ {
+ }
+
+ public MultiSelectList([NotNull] IEnumerable items, string dataValueField, string dataTextField)
+ : this(items, dataValueField, dataTextField, selectedValues: null)
+ {
+ }
+
+ public MultiSelectList(
+ [NotNull] IEnumerable items,
+ string dataValueField,
+ string dataTextField,
+ IEnumerable selectedValues)
+ : this(items, dataValueField, dataTextField, selectedValues, dataGroupField: null)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the MultiSelectList class by using the items to include in the list,
+ /// the data value field, the data text field, the selected values, and the data group field.
+ ///
+ /// The items used to build each of the list.
+ /// The data value field. Used to match the Value property of the corresponding
+ /// .
+ /// The data text field. Used to match the Text property of the corresponding
+ /// .
+ /// The selected values field. Used to match the Selected property of the
+ /// corresponding .
+ /// The data group field. Used to match the Group property of the corresponding
+ /// .
+ public MultiSelectList(
+ [NotNull] IEnumerable items,
+ string dataValueField,
+ string dataTextField,
+ IEnumerable selectedValues,
+ string dataGroupField)
+ {
+ Items = items;
+ DataValueField = dataValueField;
+ DataTextField = dataTextField;
+ SelectedValues = selectedValues;
+ DataGroupField = dataGroupField;
+
+ if (DataGroupField != null)
+ {
+ _groups = new List();
+ }
+ }
+
+ ///
+ /// Gets or sets the data group field.
+ ///
+ public string DataGroupField { get; private set; }
+
+ public string DataTextField { get; private set; }
+
+ public string DataValueField { get; private set; }
+
+ public IEnumerable Items { get; private set; }
+
+ public IEnumerable SelectedValues { get; private set; }
+
+ public virtual IEnumerator GetEnumerator()
+ {
+ return GetListItems().GetEnumerator();
+ }
+
+ internal IList GetListItems()
+ {
+ return (!string.IsNullOrEmpty(DataValueField)) ?
+ GetListItemsWithValueField() :
+ GetListItemsWithoutValueField();
+ }
+
+ private IList GetListItemsWithValueField()
+ {
+ var selectedValues = new HashSet(StringComparer.OrdinalIgnoreCase);
+ if (SelectedValues != null)
+ {
+ selectedValues.UnionWith(from object value in SelectedValues
+ select Convert.ToString(value, CultureInfo.CurrentCulture));
+ }
+
+ var listItems = from object item in Items
+ let value = Eval(item, DataValueField)
+ select new SelectListItem
+ {
+ Group = GetGroup(item),
+ Value = value,
+ Text = Eval(item, DataTextField),
+ Selected = selectedValues.Contains(value)
+ };
+ return listItems.ToList();
+ }
+
+ private IList GetListItemsWithoutValueField()
+ {
+ var selectedValues = new HashSet