web-dev-qa-db-ja.com

MVCおよびEntity Framework Html.DisplayNameForと複合ViewModel

私はWPF/Silverlightを使用したMVVMにかなり慣れていますが、これはMVC Webアプリケーションでの最初の試みです...私の背景の参考にすぎません。

Entity Frameworkモデルの「サイト」モデルクラスから自動生成されたTestSitesControllerと呼ばれるコントローラー(読み取り/書き込みアクションとビューを生成するテンプレート)を作成しました。私が変更した唯一のことは、3つの場所で、いくつかのメソッドのデフォルトパラメータがGuid id = nullであったことです。 「= null」をすべて削除したところ、問題なく動作しました。これが私が変更したものの例です

public ActionResult Delete(Guid id = null)
{
    //....
}

これはに変更されました

public ActionResult Delete(Guid id)
{
    //....
}

Siteモデルは、特別なSiteId、Abbreviation、DisplayNameなどではありません。この質問では、できるだけシンプルにしようとしています。 Okなので、ウェブサイトを実行してhtpp://.../TestSites/に移動すると、すべてが完全に機能します。

私のすべてのビュー(作成、削除、詳細、編集)が@model MVCWeb.MyEntities.Siteを使用していることに気付きました。しかし、Index.cshtmlビューでは、

@model IEnumerable<MVCWeb.MyEntities.Site>

これは、生成されたテンプレートでは問題なく機能しますが、「複合ビューモデル」を使用したいと思います。多分これは、MVVMの知識を混ぜ合わせようとしているところですが、可能であればそれを使用します。私の考えでは、複合ビューモデルは、SelectedSiteIdなどの追加のプロパティとともに1つ以上のエンティティモデルで構成されるビューに固有のモデルにすぎません。

そこで、TestSitesViewModelという非常にシンプルなViewModelを作成しました

public class TestSitesViewModel
{
    //Eventually this will be added to a base ViewModel to get rid
    //of the ViewBag dependencies
    [Display(Name = "Web Page Title")]
    public string WebPageTitle;

    public IEnumerable<MVCWeb.MyEntities.Site> Sites;

    //Other Entities, IEnumberables, or properties go here
    //Not important for this example
}

次に、コントローラにIndexWithViewModelというアクションメソッドを追加しました

public ActionResult IndexWithViewModel()
{
    var vm = new TestSitesViewModel();
    vm.WebPageTitle = "Sites With Composite View Model";
    vm.Sites = db.Sites.ToList();

    return View(vm);
}

次に、Index.cshtmlのコピーを作成し、新しいActionResultメソッド名と一致するようにIndexWithModel.cshtmlという名前を付けました。の上の行を変更しました

@model IEnumerable<MVCWeb.MyEntities.Site>

@model MVCWeb.Models.TestSitesViewModel

DisplayNameForとDisplayForをテストするために、これをテーブルセクションの前に追加しました

@Html.DisplayNameFor(model => model.WebPageTitle)
&nbsp;
@Html.DisplayFor(model => model.WebPageTitle)
<br />

を変更しました

@foreach (var item in Model) {

@foreach (var item in Model.Sites) {

とりあえず、すべてのテーブルヘッダーを含むtrセクションをコメントアウトしました。 @ Html.DisplayNameForが「Webページタイトル」を使用する代わりに「Webページタイトル」の変数名を表示していることを除いて、すべてが完全に機能します。

[Display(Name = "Web Page Title")]
public string WebPageTitle;

また、テーブルヘッダー情報を含むtrセクションでコメントを返す場合も同様です。私の人生では、私が試したmodel.Sites.Abbreviation、model.Sites [0] .Abbreviation、およびその他のさまざまな組み合わせで何を入れればよいのかわかりませんが、エラーが発生します。

<tr>
    <th>
        @Html.DisplayNameFor(model => model.Abbreviation)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.DisplayName)
    </th>
    <th></th>
</tr>

そこで私はそこで何を使うべきですか? Sitesは元のIndex.cshtmlでモデルとして使用されていたものとまったく同じタイプであるため、model.Sites.Abbreviationが機能しない理由はよくわかりません

18
Dan P

数時間いじった後、ようやくこれを理解しました。

データ注釈でDisplay引数を使用するための最初の問題は、getメソッドとsetアクセスメソッドがデフォルトのメソッドであっても追加する必要があります。これは、クラスのパブリックデータメンバーではなく、プロパティでのみ機能する必要があるためと考えています。これは取得するコードです

@Html.DisplayNameFor(model => model.WebPageTitle)

正しく機能する

public class TestSitesViewModel
{
    //Eventually this will be added to a base ViewModel to get rid of
    //the ViewBag dependencies
    [Display(Name = "Web Page Title")]
    public string WebPageTitle { get; set; }

    //PUBLIC DATA MEMBER WON'T WORK
    //IT NEEDS TO BE PROPERTY AS DECLARED ABOVE
    //public string WebPageTitle;

    public IEnumerable<MVCWeb.MyEntities.Site> Sites;

    //Other Entities, IEnumberables, or properties go here
    //Not important for this example
}

問題の2番目の部分は、IEnumerable変数のメタデータにアクセスすることでした。 headerMetadataという一時変数を宣言し、IEnumerableを介してプロパティにアクセスする代わりにそれを使用しました

@{var headerMetadata = Model.Sites.FirstOrDefault();}
<tr>
    <th>            
        @Html.DisplayNameFor(model => headerMetadata.Abbreviation)
    </th>
    <th>
        @Html.DisplayNameFor(model => headerMetadata.DisplayName)
    </th>
    ...

これは、headerMetadata変数がいつスコープから外れるのかという疑問を引き起こしますか?ビュー全体で使用できますか、それともhtmlテーブルタグに限定されますか?それは別の日付の別の質問だと思います。

21
Dan P

私は新しく学んだMVVM ASP.NET MVCエクスペリエンスを試してみます。

@Html.DisplayNameFor(model => model.WebPageTitle)を呼び出す代わりに、@Html.DisplayFor(model => model.WebPageTitle)を使用してみてください。ビューに表示されるIndexWithViewModelコントローラーでWebPageTitle値を設定しているようです。

ASP.NET MVCの共有 templates を調べます。 DisplayFor/EditorForヘルパーのカスタムテンプレートまたはパーシャルを/Views/Shared/EditorTemplates/Site.cshtmlおよび/Views/Shared/DisplayTemplates/Site.cshtmlで設定できます。 ASP.NET MVCは、DisplayForおよびEditorForでサイトオブジェクトをレンダリングするときに、これらのテンプレートを自動的に選択します。

幸運を!

1
Brett