Question

J'ai un modèle comme ceci:

public class MainModel
{
   public string Id {get;set;}
   public string Title {get;set;}
   public TimePicker TimePickerField {get;set;}
}

TimePicker est un modèle intérieur qui ressemble à ceci:

public class TimePicker 
{
   public TimeSpan {get;set;}
   public AmPmEnum AmPm {get;set;}
}

J'essaie de créer une liaison de modèle personnalisée pour le modèle intérieur: TimePicker

La question est: comment puis-je obtenir des valeurs dans le classeur de modèle personnalisé qui a été soumis sous forme TimePicker champs modèles?

Si j'essaye de l'obtenir comme ceci:

var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

Je viens juste null dans value.

Je ne sais pas comment implémenter correctement le classeur du modèle.

public class TimePickerModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException("bindingContext");
        }
        var result = new TimePicker();

        var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (value != null)
        {
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);
            try
            {
                //result = Duration.Parse(value.AttemptedValue);
            }
            catch (Exception ex)
            {
               bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex.Message);
            }
        }    

        return result;
    }
}
Était-ce utile?

La solution

Ce qui suit fonctionne pour moi.

Modèle:

public enum AmPmEnum
{
    Am, 
    Pm
}

public class TimePicker 
{
    public TimeSpan Time { get; set; }
    public AmPmEnum AmPm { get; set; }
}

public class MainModel
{
    public TimePicker TimePickerField { get; set; }
}

Manette:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MainModel
        {
            TimePickerField = new TimePicker
            {
                Time = TimeSpan.FromHours(1),
                AmPm = AmPmEnum.Pm
            }
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(MainModel model)
    {
        return View(model);
    }
}

Voir (~/Views/Home/Index.cshtml):

@model MainModel
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.TimePickerField)
    <button type="submit">OK</button>
}

Modèle d'éditeur personnalisé (~/Views/Shared/EditorTemplates/TimePicker.cshtml) qui fusionne le Time et AmPm Propriétés en un seul champ de saisie et qui nécessitera un liant de modèle personnalisé plus tard afin de les diviser lorsque le formulaire est soumis:

@model TimePicker
@Html.TextBox("_picker_", string.Format("{0} {1}", Model.Time, Model.AmPm))

Et le classeur du modèle:

public class TimePickerModelBinder : IModelBinder
{
    public object BindModel(
        ControllerContext controllerContext, 
        ModelBindingContext bindingContext
    )
    {
        var key = bindingContext.ModelName + "._picker_";
        var value = bindingContext.ValueProvider.GetValue(key);
        if (value == null)
        {
            return null;
        }

        var result = new TimePicker();

        try
        {
            // TODO: instead of hardcoding do your parsing
            // from value.AttemptedValue which will contain the string
            // that was entered by the user
            return new TimePicker
            {
                Time = TimeSpan.FromHours(2),
                AmPm = AmPmEnum.Pm
            };
        }
        catch (Exception ex)
        {
            bindingContext.ModelState.AddModelError(
                bindingContext.ModelName, 
                ex.Message
            );
            // This is important in order to preserve the original user
            // input in case of error when redisplaying the view
            bindingContext.ModelState.SetModelValue(key, value);
        }
        return result;
    }
}

Et enfin enregistrer votre classeur de modèle dans Application_Start:

ModelBinders.Binders.Add(typeof(TimePicker), new TimePickerModelBinder());
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top