4

私はこのようなモデルだ:カスタムモデルバインダー

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

TimePickerを次のようになり、内部モデルである:

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

私はカスタムモデルバインディングを作成しようとしています内部モデル用:TimePicker

質問:フォームにサブミットされたカスタムモデルバインダーの値をTimePickerモデルに取得する方法フィールド?

私はこのようにそれを取得しようとした場合:私はちょうどvaluenullを取得

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

モデルバインダーを正しく実装する方法がわかりません。

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

あなたの質問から、どのような値が提出され、どのように表示されるかは不明です。なぜこのモデルにカスタムモデルのバインダーが必要なのか、その目的が正確になるのかははっきりしていません。また、 'IModelBinder'を直接実装しているのか、' DefaultModelBinder'をサブクラス化しているのかは明らかではありません。もう一つは、このモデルバインダーのどのメソッドで、 'bindingContext.ValueProvider.GetValue(bindingContext.ModelName);'を呼び出そうとしているのですか?(明らかに、IModelBinderを直接実装する場合は、単一のメソッドがあります:BindModel) 。 –

+0

ビューには、時間のあるテキストフィールドと、PM/AM選択のある2つのラジオボタンという2つのフィールドがあります。実装する必要があるかIModelBinderを直接またはサブクラスDefaultModelBinderか分からない。それについてアドバイスを受けるのは本当にいいですね。はい私はBindModelでそれを呼び出す私のバインダーを私の質問に追加しました。 – Mindaugas

+0

あなたのコードを見る機会がありますか?また、カスタムモデルバインダーがなぜ必要なのか、私の質問には答えませんでした。あなたは正確に何を達成しようとしていますか? –

答えて

11

次のように動作します。

モデル:

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

コントローラー:

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

ビュー(~/Views/Home/Index.cshtml):シングルへTimeAmPmプロパティをマージし

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

カスタムエディタのテンプレート(~/Views/Shared/EditorTemplates/TimePicker.cshtml)入力フィールフォームが送信されたときにそれらを分割するために、カスタムモデルバインダーを後で必要となるDと:

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

とモデルバインダー:

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

、最終的にはApplication_Startであなたのモデルバインダーを登録します。

ModelBinders.Binders.Add(typeof(TimePicker), new TimePickerModelBinder()); 
+0

ありがとうございました。私は少し違った形で作ったが、答えは本当に充実していた。ありがとうございました! – Mindaugas

関連する問題