75 votes

Quelqu'un a-t-il implémenté RadioButtonListFor? <T> pour ASP.NET MVC?

Il y avait une méthode d'extension Html.RadioButtonList dans ASP.NET MVC Futures. Quelqu'un at-il trouvé un code pour une version fortement typée RadioButtonListFor<T> . Cela ressemblerait à ceci dans une vue:

 <%= Html.RadioButtonListFor(model=>model.Item,Model.ItemList) %>
 

88voto

Mac Points 1960

Voici l'utilisation dans la page aspx

     <%= Html.RadioButtonListFor(m => m.GenderRadioButtonList)%>
 

Voici le modèle de vue

 public class HomePageViewModel
{
    public enum GenderType
    {
        Male,
        Female
    }
    public RadioButtonListViewModel<GenderType> GenderRadioButtonList { get; set; }

    public HomePageViewModel()
    {
        GenderRadioButtonList = new RadioButtonListViewModel<GenderType>
        {
            Id = "Gender",
            SelectedValue = GenderType.Male,
            ListItems = new List<RadioButtonListItem<GenderType>>
            {
                new RadioButtonListItem<GenderType>{Text = "Male", Value = GenderType.Male},
                new RadioButtonListItem<GenderType>{Text = "Female", Value = GenderType.Female}
            }
        };
    }
}
 

Voici le modèle de vue utilisé pour les listes de boutons radio

 public class RadioButtonListViewModel<T>
{
    public string Id { get; set; }
    private T selectedValue;
    public T SelectedValue
    {
        get { return selectedValue; }
        set
        {
            selectedValue = value;
            UpdatedSelectedItems();
        }
    }

    private void UpdatedSelectedItems()
    {
        if (ListItems == null)
            return;

        ListItems.ForEach(li => li.Selected = Equals(li.Value, SelectedValue));
    }

    private List<RadioButtonListItem<T>> listItems;
    public List<RadioButtonListItem<T>> ListItems
    {
        get { return listItems; }
        set
        {
            listItems = value;
            UpdatedSelectedItems();
        }
    }
}

public class RadioButtonListItem<T>
{
    public bool Selected { get; set; }

    public string Text { get; set; }

    public T Value { get; set; }

    public override string ToString()
    {
        return Value.ToString();
    }
}
 

Voici les méthodes d'extension pour RadioButtonListFor

 public static class HtmlHelperExtensions
{
    public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression) where TModel : class
    {
        return htmlHelper.RadioButtonListFor(expression, null);
    }

    public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression, object htmlAttributes) where TModel : class
    {
        return htmlHelper.RadioButtonListFor(expression, new RouteValueDictionary(htmlAttributes));
    }

    public static string RadioButtonListFor<TModel, TRadioButtonListValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, RadioButtonListViewModel<TRadioButtonListValue>>> expression, IDictionary<string, object> htmlAttributes) where TModel : class
    {
        var inputName = GetInputName(expression);

        RadioButtonListViewModel<TRadioButtonListValue> radioButtonList = GetValue(htmlHelper, expression);

        if (radioButtonList == null)
            return String.Empty;

        if (radioButtonList.ListItems == null)
            return String.Empty;

        var divTag = new TagBuilder("div");
        divTag.MergeAttribute("id", inputName);
        divTag.MergeAttribute("class", "radio");
        foreach (var item in radioButtonList.ListItems)
        {
            var radioButtonTag = RadioButton(htmlHelper, inputName, new SelectListItem{Text=item.Text, Selected = item.Selected, Value = item.Value.ToString()}, htmlAttributes);

            divTag.InnerHtml += radioButtonTag;
        }

        return divTag + htmlHelper.ValidationMessage(inputName, "*");
    }

    public static string GetInputName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
    {
        if (expression.Body.NodeType == ExpressionType.Call)
        {
            var methodCallExpression = (MethodCallExpression)expression.Body;
            string name = GetInputName(methodCallExpression);
            return name.Substring(expression.Parameters[0].Name.Length + 1);

        }
        return expression.Body.ToString().Substring(expression.Parameters[0].Name.Length + 1);
    }

    private static string GetInputName(MethodCallExpression expression)
    {
        // p => p.Foo.Bar().Baz.ToString() => p.Foo OR throw...

        var methodCallExpression = expression.Object as MethodCallExpression;
        if (methodCallExpression != null)
        {
            return GetInputName(methodCallExpression);
        }
        return expression.Object.ToString();
    }

    public static string RadioButton(this HtmlHelper htmlHelper, string name, SelectListItem listItem,
                         IDictionary<string, object> htmlAttributes)
    {
        var inputIdSb = new StringBuilder();
        inputIdSb.Append(name)
            .Append("_")
            .Append(listItem.Value);

        var sb = new StringBuilder();

        var builder = new TagBuilder("input");
        if (listItem.Selected) builder.MergeAttribute("checked", "checked");
        builder.MergeAttribute("type", "radio");
        builder.MergeAttribute("value", listItem.Value);
        builder.MergeAttribute("id", inputIdSb.ToString());
        builder.MergeAttribute("name", name + ".SelectedValue");
        builder.MergeAttributes(htmlAttributes);
        sb.Append(builder.ToString(TagRenderMode.SelfClosing));
        sb.Append(RadioButtonLabel(inputIdSb.ToString(), listItem.Text, htmlAttributes));
        sb.Append("<br>");

        return sb.ToString();
    }

    public static string RadioButtonLabel(string inputId, string displayText,
                                 IDictionary<string, object> htmlAttributes)
    {
        var labelBuilder = new TagBuilder("label");
        labelBuilder.MergeAttribute("for", inputId);
        labelBuilder.MergeAttributes(htmlAttributes);
        labelBuilder.InnerHtml = displayText;

        return labelBuilder.ToString(TagRenderMode.Normal);
    }


    public static TProperty GetValue<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression) where TModel : class
    {
        TModel model = htmlHelper.ViewData.Model;
        if (model == null)
        {
            return default(TProperty);
        }
        Func<TModel, TProperty> func = expression.Compile();
        return func(model);
    }
}
 

26voto

Jon Points 368

Exemple MVC 3 qui crée 3 boutons radio avec validation pour s’assurer que 1 option est sélectionnée. Et si la validation du formulaire échoue (par exemple sur d’autres champs), l’option radio choisie est présélectionnée lors de la nouvelle présentation du formulaire.

Vue

 @Html.RadioButtonForSelectList(m => m.TestRadio, Model.TestRadioList)
@Html.ValidationMessageFor(m => m.TestRadio)
 

Modèle

 public class aTest
{
    public Int32 ID { get; set; }
    public String Name { get; set; }
}

public class LogOnModel
{
    public IEnumerable<SelectListItem> TestRadioList { get; set; }

    [Required(ErrorMessage="Test Error")]
    public String TestRadio { get; set; }

    [Required]
    [Display(Name = "User name")]
    public string UserName { get; set; }
}
 

Actions du contrôleur

 public ActionResult LogOn()
    {
        List<aTest> list = new List<aTest>();
        list.Add(new aTest() { ID = 1, Name = "Line1" });
        list.Add(new aTest() { ID = 2, Name = "Line2" });
        list.Add(new aTest() { ID = 3, Name = "Line3" });

        SelectList sl = new SelectList(list, "ID", "Name");

        var model = new LogOnModel();
        model.TestRadioList = sl;

        return View(model);
    }

    [HttpPost]
    public ActionResult LogOn(LogOnModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
             ....
        }

        // If we got this far, something failed, redisplay form
        List<aTest> list = new List<aTest>();
        list.Add(new aTest() { ID = 1, Name = "Line1" });
        list.Add(new aTest() { ID = 2, Name = "Line2" });
        list.Add(new aTest() { ID = 3, Name = "Line3" });

        SelectList sl = new SelectList(list, "ID", "Name");
        model.TestRadioList = sl;

        return View(model);
    }
 

Voici l'extension:

 public static class HtmlExtensions
{
    public static MvcHtmlString RadioButtonForSelectList<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        IEnumerable<SelectListItem> listOfValues)
    {
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        var sb = new StringBuilder();

        if (listOfValues != null)
        {
            foreach (SelectListItem item in listOfValues)
            {
                var id = string.Format(
                    "{0}_{1}",
                    metaData.PropertyName,
                    item.Value
                );

                var radio = htmlHelper.RadioButtonFor(expression, item.Value, new { id = id }).ToHtmlString();
                sb.AppendFormat(
                    "<label for=\"{0}\">{1}</label> {2}",
                    id,
                    HttpUtility.HtmlEncode(item.Text),
                    radio
                );
            }
        }

        return MvcHtmlString.Create(sb.ToString());
    }
}
 

2voto

Jay Points 1450

Bon, je suis conscient que ce n'est pas une réponse directe à votre question, mais cela peut être une meilleure façon de faire la plupart des intrants de toute façon (et c'était amusant à faire). Je viens à peine terminé cette et a couru une petite quantité de tester contre, donc je ne peux pas se porter garant de cet être parfait dans chaque situation.

J'ai eu cette idée de Jimmy Bogard post ici. Prendre un coup d'oeil car il y a un tas d'idées vraiment cool.

Ce que j'ai fait il est créé une "InputFor" helper qui essaie de son mieux de travailler sur l'entrée que vous demandez et les sorties en conséquence. Cela va faire des boutons radio, mais par défaut une liste déroulante si il n'y a plus de deux, vous devriez être en mesure de modifier cette fonctionnalité assez facilement.

Le code ci-dessous permet de faire des appels comme <%= Html.InputFor(m => m.Gender) %> ou <%Html.InputFor(m => m.Gender, Model.GenderList)%>. Il y a un peu de fraîcheur peu à la fin qui permet de faire le codage par la convention, mais nous y reviendrons plus tard.

public static MvcHtmlString InputFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, object>> field, Dictionary<string, string> listing) where TModel : class
        {
            string property_name = GetInputName(field);
            PropertyDescriptor descriptor = TypeDescriptor.GetProperties(helper.ViewData.Model).Find(property_name, true);
            string property_type = descriptor.PropertyType.Name;
            var func = field.Compile();
            var value = func(helper.ViewData.Model);

            //Add hidden element if required
            if (descriptor.Attributes.Contains(new HiddenInputAttribute()))
            {
                return helper.Hidden(property_name, value);
            }

            if (property_type == "DateTime" || property_type == "Date")
            {
                return helper.TextBox(property_name, value, new { @class = "date_picker" });
            }
            if (listing != null)
            {
                if (listing.Count <= 2)
                {
                    //This is a good length for a radio button
                    string output = "";
                    foreach (KeyValuePair<string, string> pair in listing)
                    {
                        TagBuilder label = new TagBuilder("label");
                        label.MergeAttribute("for", property_name);
                        label.SetInnerText(pair.Value);
                        output += helper.RadioButton(property_name, pair.Key, (value == pair.Key)).ToHtmlString();
                        output += label.ToString();
                    }
                    return MvcHtmlString.Create(output);
                }
                else
                {
                    //too big for a radio button, lets make a drop down
                    return helper.DropDownList(property_name, new SelectList(listing, "Key", "Value"), value);
                }
            }
            else
            {
                if (property_type == "Boolean")
                {
                    listing = new Dictionary<string, string>();
                    listing.Add("true", "Yes");
                    listing.Add("false", "No");
                    SelectList select_values = new SelectList(listing, "Key", "Value", ((bool)value ? "Yes" : "No"));
                    return helper.DropDownList(property_name, select_values);
                }
                return helper.TextBox(property_name, value);
            }
        }

Codage par Convention

Le code ci-dessous permet de le faire avec la convention over configuration à l'esprit. Un exemple de ceci est que si vous avez un modèle objet qui contient la propriété que vous souhaitez ajouter à la liste (le Sexe) et un dictionnaire avec le même nom, mais se terminant par "Liste" (GenderList) puis il va utiliser cette liste par défaut.

par exemple, <%= Html.InputFor(m => m.Gender) %> peut faire une liste déroulante/groupe de boutons radio, mais ces valeurs par défaut peuvent être remplacés par un appel comme <%= Html.InputFor(m => m.Gender, alternate_list) %>

public static MvcHtmlString InputFor<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, object>> field) where TModel : class
{
    string property_name = GetInputName(field) + "List";
    PropertyDescriptor list_descriptor = TypeDescriptor.GetProperties(helper.ViewData.Model).Find(property_name, true);
    Dictionary<string, string> listing = null;

    if (list_descriptor != null)
    {
        //Found a match for PropertyNameList, try to pull it out so we can use it
        PropertyInfo temp = helper.ViewData.Model.GetType().GetProperty(property_name);
        listing = (Dictionary<string, string>)temp.GetValue(helper.ViewData.Model, null);
    }
    return InputFor(helper, field, listing);
}

Maintenant un léger avertissement:

  • Ce n'est pas le plus rapide de code dans le monde (à cause de la réflexion et d'autres choses), dans ma situation, ce n'est pas vraiment pertinente, car elle est tout axé sur l'utilisateur, si vous avez l'intention de faire quelque chose de fou stupide.
  • Ce code est à ses balbutiements, je vais tester cela de manière plus approfondie et d'en ajouter au cours des prochains jours, ouvert à toutes suggestions pour améliorer le code.

J'espère que ce code est utile à quelqu'un, je sais que je vais l'utiliser au cours de la prochaine quelques semaines pour essayer et réduire les temps. La coupe de ce vers le bas pour faire juste le bouton radio devrait être une tâche facile, bonne chance :)

Jay

2voto

Pedre Points 196

Basé dans Jon post , une petite amélioration pour générer la liste de boutons radio comme ul avec HTMLAttributtes

 public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        IEnumerable<SelectListItem> listOfValues,
        IDictionary<string, object> radioHtmlAttributes = null,
        string ulClass = null)
    {
        ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        if (radioHtmlAttributes == null)
            radioHtmlAttributes = new RouteValueDictionary();

        TagBuilder ulTag = new TagBuilder("ul");
        if (!String.IsNullOrEmpty(ulClass))
            ulTag.MergeAttribute("class", ulClass);

        if (listOfValues != null)
        {
            // Create a radio button for each item in the list 
            foreach (SelectListItem item in listOfValues)
            {

                // Generate an id to be given to the radio button field 
                var id = string.Format("{0}_{1}", metaData.PropertyName, item.Value);

                if (!radioHtmlAttributes.ContainsKey("id"))
                    radioHtmlAttributes.Add("id", id);
                else
                    radioHtmlAttributes["id"] = id;

                // Create and populate a radio button using the existing html helpers 
                var label = htmlHelper.Label(id, HttpUtility.HtmlEncode(item.Text));
                var radio = htmlHelper.RadioButtonFor(expression, item.Value, radioHtmlAttributes).ToHtmlString();

                // Create the html string that will be returned to the client 
                // e.g. <input data-val="true" data-val-required="You must select an option" id="TestRadio_1" name="TestRadio" type="radio" value="1" /><label for="TestRadio_1">Line1</label> 
                ulTag.InnerHtml += string.Format("<li>{0}{1}</li>", radio, label);
            }
        }

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

    public static MvcHtmlString RadioButtonListFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        IEnumerable<SelectListItem> listOfValues,
        object radioHtmlAttributes = null,
        string ulClass = null)
    {
        return RadioButtonListFor<TModel, TProperty>(htmlHelper, expression, listOfValues, new RouteValueDictionary(radioHtmlAttributes), ulClass);
    }
 

1voto

Naweed Akram Points 21

J'ai mis en place quelque chose de similaire dans MVC 1.0. Voir si ce sera utile pour vous:

    public static string RadioButtonList2(this HtmlHelper _helper, string _name, IEnumerable<SelectListItem> _items, string _selectedValue, string _seperator)
    {
        return RadioButtonList2(_helper, _name, _items, _selectedValue, _seperator, null);
    }

    public static string RadioButtonList2(this HtmlHelper _helper, string _name, IEnumerable<SelectListItem> _items, string _selectedValue, string _seperator, IDictionary<string, object> _htmlAttributes)
    {
        StringBuilder _outputScript = new StringBuilder();

        foreach (var item in _items)
        {
            var optionField = new TagBuilder("input");
            optionField.MergeAttribute("name", _name);
            optionField.MergeAttribute("id", _name);
            optionField.MergeAttribute("class", _name);
            optionField.MergeAttribute("value", item.Value);
            optionField.MergeAttribute("type", "radio");

            // Check to see if it's checked
            if (item.Value == _selectedValue)
                optionField.MergeAttribute("checked", "checked");

            if (_htmlAttributes != null)
                optionField.MergeAttributes(_htmlAttributes);

            _outputScript.Append(optionField.ToString(TagRenderMode.SelfClosing));
            _outputScript.Append("<label style=\"display:inline;\">");
            _outputScript.Append(item.Text);
            _outputScript.Append("</label>" + _seperator);
        }

        return _outputScript.ToString();
    }

Dans le contrôleur, vous pouvez retourner le résultat comme suit:

        ViewData["GenderList"] = new SelectList(new[] { new { Value = "M", Text = "Male" }, new { Value = "F", Text = "Female" }, new { Value = "A", Text = "All" } }, "Value", "Text");

ou

        ViewData["GenderList"] = new SelectList(_resultFromSomeLinqQuery, "GenderID", "GenderName");

Et de l'utiliser dans la Vue comme suit:

<%= Html.RadioButtonList2("Sex", ViewData["GenderList"] as SelectList, ViewData["SelectedSex"].ToString(), "&nbsp;")%>

Vous pouvez également remplacer l' &nbsp; avec <BR /> pour les afficher sous la forme de plusieurs lignes.

Espérons que cette aide.

Ce qui concerne Naweed Akram naweed@xgeno.com

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X