Кто-либо сделал, реализуют RadioButtonListFor <T> для ASP.NET MVC?

Был Html.RadioButtonList дополнительный метод в ASP.NET фьючерсы MVC. Имеет любого, нашел код для версии со строгим контролем типов RadioButtonListFor<T>. Это было бы похоже на это в представлении:

<%= Html.RadioButtonListFor(model=>model.Item,Model.ItemList) %>
75
задан Keltex 7 April 2010 в 15:21
поделиться

3 ответа

Вот использование на странице aspx

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

Вот модель представления

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}
            }
        };
    }
}

Вот модель представления, используемая для списков переключателей

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();
    }
}

Вот методы расширения для 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);
    }
}
88
ответ дан 24 November 2019 в 11:40
поделиться

Хорошо, я понимаю, что это не прямой ответ на ваш вопрос, но в любом случае это может быть лучший способ внести большинство вкладов (и это было весело). Я только что завершил это и провел небольшое количество тестов, поэтому я не могу поручиться за то, что это идеально в любой ситуации.

Я почерпнул эту идею из сообщения Джимми Богарда здесь . Взгляните, потому что там куча действительно крутых идей.

Я создал помощника "InputFor", который изо всех сил пытается определить, какой ввод вы запрашиваете, и соответственно выводит его. Это будет делать переключатели, но по умолчанию будет выпадающий список, если их больше двух, вы сможете довольно легко изменить эту функцию.

Приведенный ниже код позволяет выполнять такие вызовы, как <% = Html.InputFor (m => m.Gender)%> или <% Html.InputFor (m => m. Пол, Model.GenderList)%> . В конце есть крутая деталь, которая позволяет вам кодировать по соглашению, но мы вернемся к этому позже.

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);
            }
        }

Кодирование по соглашению

Приведенный ниже код позволяет сделать это, имея в виду соглашение, а не конфигурацию. Например, если у вас есть объект модели, который содержит свойство, которое вы хотите перечислить (Gender), и словарь с тем же именем, но с добавлением «List» (GenderList), то он будет использовать этот список по умолчанию.

например. <% = Html.InputFor (m => m.Gender)%> может создать полный раскрывающийся список / группу переключателей, но эти значения по умолчанию можно изменить, сделав вызов типа < % = 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);
}

Теперь небольшой отказ от ответственности:

  • Это не самый быстрый код в мире (из-за отражения и прочего), в моей ситуации это не совсем актуально, так как все пользовательские управляемый, если вы планируете совершить что-то безумно глупое.
  • Этот код находится в зачаточном состоянии, я буду тестировать его более тщательно и добавлять к нему в течение следующих нескольких дней, открыт для любых предложений по улучшению кода.

Я надеюсь, что этот код будет кому-то полезен, я знаю, что буду использовать его в течение следующих двух недель, чтобы попытаться сократить время. Сократить это до переключателя должно быть тривиальной задачей, удачи :)

Джей

2
ответ дан 24 November 2019 в 11:40
поделиться

Я реализовал нечто подобное в MVC 1.0. Посмотрите, может это будет вам полезно:

    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();
    }

В контроллере вы можете вернуть результат следующим образом:

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

или

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

И использовать его в представлении следующим образом:

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

Вы также можете заменить   на
, чтобы отобразить их в отдельных строках.

Надеюсь, это поможет.

С уважением Навид Акрам naweed@xgeno.com

1
ответ дан 24 November 2019 в 11:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: