3

私はこのクラスを持っています

public class Contact
{
    public int Id { get; set; }
    public string ContaSurname { get; set; }
    public string ContaFirstname { get; set; }
    // and other properties...
}

そして、これらすべてのフィールドを編集できるフォームを作成したいと考えています。だから私はこのコードを使用しました

<h2>Contact Record</h2>

@Html.EditorFor(c => Model.Contact)

これで問題なく動作しますが、要素の表示方法をカスタマイズしたいと考えています。たとえば、各フィールドをそのラベルと同じ行に表示したいとします。今、生成された html は次のようになっているためです。

<div class="editor-label">
  <label for="Contact_ContaId">ContaId</label>
</div>
<div class="editor-field">
  <input id="Contact_ContaId" class="text-box single-line" type="text" value="108" name="Contact.ContaId">
</div>
4

2 に答える 2

4

上記の jrummell の解決策に同意します。-Extension を使用する場合EditorFor、ビジュアル コンポーネントを記述するカスタム エディター テンプレートを作成する必要があります。

場合によっては、同じデータ型の複数のモデル プロパティに対してエディター テンプレートを使用するのは少し難しいと思います。私の場合、フォーマットされた文字列として表示されるモデルで 10 進数の通貨値を使用したいと考えています。ビューで対応する CSS クラスを使用して、これらのプロパティのスタイルを設定したいと考えています。

モデルの注釈を使用して HTML パラメータがプロパティに追加されている他の実装を見てきました。CSS定義のようなビュー情報は、データモデルではなくビューに設定する必要があるため、これは私の意見では悪いです。

したがって、私は別の解決策に取り組んでいます:

私のモデルにはdecimal?、通貨フィールドとして使用したいプロパティが含まれています。問題は、モデルでデータ型を使用したいのですがdecimal?、フォーマット マスクを使用してフォーマットされた文字列としてビューに 10 進値を表示することです (例: "42,13 €")。

これが私のモデル定義です:

[DataType(DataType.Currency), DisplayFormat(DataFormatString = "{0:C2}", ApplyFormatInEditMode = true)]
public decimal? Price { get; set; }

フォーマット マスクは、小数点以下 2 桁で0:C2フォーマットします。decimalこのApplyFormatInEditModeプロパティを使用してビューの編集可能なテキスト フィールドに入力する場合、これは重要です。true私の場合はテキストフィールドに入れたいので、に設定しました。

通常、次EditorForのようにビューで -Extensionを使用する必要があります。

<%: Html.EditorFor(x => x.Price) %>

問題:

Html.TextBoxForたとえば、CSS クラスをここに追加することはできません。

-Extensionを使用して独自の CSS クラス (または や などの他の HTML 属性tabindex)readonlyを提供するには、 のようなカスタム HTML ヘルパーを記述します。実装は次のとおりです。EditorForHtml.CurrencyEditorFor

public static MvcHtmlString CurrencyEditorFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, Object htmlAttributes)
{
  TagBuilder tb = new TagBuilder("input");

  // We invoke the original EditorFor-Helper
  MvcHtmlString baseHtml = EditorExtensions.EditorFor<TModel, TValue>(html, expression);

  // Parse the HTML base string, to refurbish the CSS classes
  string basestring = baseHtml.ToHtmlString();

  HtmlDocument document = new HtmlDocument();
  document.LoadHtml(basestring);
  HtmlAttributeCollection originalAttributes = document.DocumentNode.FirstChild.Attributes;

  foreach(HtmlAttribute attr in originalAttributes) {
    if(attr.Name != "class") {
      tb.MergeAttribute(attr.Name, attr.Value);
    }
  }

  // Add the HTML attributes and CSS class from the View
  IDictionary<string, object> additionalAttributes = (IDictionary<string, object>) HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

  foreach(KeyValuePair<string, object> attribute in additionalAttributes) {
    if(attribute.Key == "class") {
      tb.AddCssClass(attribute.Value.ToString());
    } else {
      tb.MergeAttribute(attribute.Key, attribute.Value.ToString());
    }
  }

  return MvcHtmlString.Create(HttpUtility.HtmlDecode(tb.ToString(TagRenderMode.SelfClosing)));
}

元のEditorFor-Extension を使用して HTML コードを生成し、この HTML 出力文字列を解析して、作成された CSS Html-Attribute を独自の CSS クラスに置き換え、他の HTML 属性を追加するという考え方です。HTML の解析には、HtmlAgilityPack (Google を使用) を使用します。

web.configビューでは、このヘルパーを次のように使用できます (対応する名前空間をビュー ディレクトリに配置することを忘れないでください!):

<%: Html.CurrencyEditorFor(x => x.Price, new { @class = "mypricestyles", @readonly = "readonly", @tabindex = "-1" }) %>

このヘルパーを使用すると、通貨の値がビューに適切に表示されるはずです。

ビュー (フォーム) を投稿する場合、通常、すべてのモデル プロパティがコントローラーのアクション メソッドに送信されます。この場合、文字列形式の 10 進数値が送信され、ASP.NET MVC 内部モデル バインディング クラスによって処理されます。

このモデル バインダーはdecimal?-value を想定していますが、文字列形式の値を取得するため、例外がスローされます。そのため、フォーマットされた文字列を元のdecimal?表現に変換する必要があります。したがって、ModelBinder通貨の 10 進値をデフォルトの 10 進値に変換する独自の実装が必要です ("42,13 €" => "42.13")。

このようなモデル バインダーの実装を次に示します。

public class DecimalModelBinder : IModelBinder
{

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
      object o = null;
      decimal value;

      var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
      var modelState = new ModelState { Value = valueResult };

      try {

        if(bindingContext.ModelMetadata.DataTypeName == DataType.Currency.ToString()) {
          if(decimal.TryParse(valueResult.AttemptedValue, NumberStyles.Currency, null, out value)) {
            o = value;
          }
        } else {
          o = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.CurrentCulture);
        }

      } catch(FormatException e) {
        modelState.Errors.Add(e);
      }

      bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
      return o;
    }
}

バインダーはglobal.asax、アプリケーションのファイルに登録する必要があります。

protected void Application_Start()
{
    ...

    ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
    ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());

    ...
}

多分解決策は誰かを助けるでしょう。

于 2013-02-04T13:00:00.210 に答える
3

Contact.cshtmlのカスタム マークアップで呼び出される部分ビューを作成しますViews/Shared/EditorTemplates。これにより、デフォルトのエディターがオーバーライドされます。

@smartcavemen が指摘したように、テンプレートの概要については、 Brad Wilson のブログを参照してください。

于 2012-10-01T14:54:49.747 に答える