文字列のLayoutプロパティが表示されます。しかし、モデルをレイアウトに明示的に渡すにはどうすればよいですか?
Model
で利用可能です_Layout
。MVC5を使用しています。
文字列のLayoutプロパティが表示されます。しかし、モデルをレイアウトに明示的に渡すにはどうすればよいですか?
Model
で利用可能です_Layout
。MVC5を使用しています。
回答:
この問題がある場合、ビューモデルを少し間違ってモデリングしたようです。
個人的には、レイアウトページを入力することはありません。ただし、それを行う場合は、他のビューモデルが継承する基本ビューモデルを用意し、基本ビューモデルにレイアウトを入力して、特定のページにページを移動する必要があります。
例:コントローラ:
public class MyController : Controller
{
public MainLayoutViewModel MainLayoutViewModel { get; set; }
public MyController()
{
this.MainLayoutViewModel = new MainLayoutViewModel();//has property PageTitle
this.MainLayoutViewModel.PageTitle = "my title";
this.ViewData["MainLayoutViewModel"] = this.MainLayoutViewModel;
}
}
レイアウトページの上部の例
@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}
これで、型付きオブジェクトへの完全なアクセス権を持つレイアウトページで変数「viewModel」を参照できます。
レイアウトを制御するのはコントローラーであり、個々のページビューモデルはレイアウトにとらわれないため、このアプローチが好きです。
MVCコアに関する注意
IActionFilter
でまったく同じ機能を実行することOnActionExecuting
です。あなたを着MyActionFilter
てくださいMyController
。
public class MyActionFilter: Attribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext context)
{
}
public void OnActionExecuting(ActionExecutingContext context)
{
var myController= context.Controller as MyController;
if (myController!= null)
{
myController.Layout = new MainLayoutViewModel
{
};
myController.ViewBag.MainLayoutViewModel= myController.Layout;
}
}
}
これはかなり基本的なものです。ベースビューモデルを作成し、すべてを確認するだけです。そして私はすべてを意味します!そのレイアウトを使用するビューのうち、そのベースモデルを使用するビューを受け取ります。
public class SomeViewModel : ViewModelBase
{
public bool ImNotEmpty = true;
}
public class EmptyViewModel : ViewModelBase
{
}
public abstract class ViewModelBase
{
}
_Layout.cshtml:
@model Models.ViewModelBase
<!DOCTYPE html>
<html>
and so on...
ホームコントローラーの(たとえば)インデックスメソッドで:
public ActionResult Index()
{
var model = new SomeViewModel()
{
};
return View(model);
}
Index.cshtml:
@model Models.SomeViewModel
@{
ViewBag.Title = "Title";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
モデルを_layoutに渡すことはエラーであることに同意しません。一部のユーザー情報を渡すことができ、データはコントローラーの継承チェーンに入力できるため、1つの実装のみが必要です。
明らかに、より高度な目的のために、インジェクションを使用してカスタム静的contaxtを作成することを検討し、そのモデルの名前空間を_Layout.cshtmlに含める必要があります。
しかし、基本的なユーザーの場合、これはトリックを行います
一般的な解決策は、レイアウトファイルで使用されるプロパティを含むベースビューモデルを作成し、ベースモデルから各ページで使用されるモデルに継承することです。
このアプローチの問題は、モデルの問題に固執し、他の1つのクラスからのみ継承できることです。おそらく、意図したモデルで継承を使用できないようなソリューションである可能性があります。
私のソリューションもベースビューモデルから始まります。
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
次に使用するのは、次のように、LayoutModelから継承するLayoutModelの汎用バージョンです。
public class LayoutModel<T> : LayoutModel
{
public LayoutModel(T pageModel, string title) : base(title)
{
PageModel = pageModel;
}
public T PageModel { get; }
}
このソリューションにより、レイアウトモデルとモデルの間で継承を行う必要がなくなりました。
これで、Layout.cshtmlのLayoutModelを次のように使用できます。
@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
そして、ページでは次のような一般的なLayoutModelを使用できます。
@model LayoutModel<Customer>
@{
var customer = Model.PageModel;
}
<p>Customer name: @customer.Name</p>
コントローラーから、タイプLayoutModelのモデルを返すだけです。
public ActionResult Page()
{
return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}
必要なモデルを部分ビューに渡し、独自の特定のコントローラーを備えた新しい部分ビューを追加して、最後に、RenderPartialまたはRenderActionを使用して、Layout.cshtmlで上記の部分ビューをレンダリングしないでください。
この方法を使用して、ログインしたユーザーの名前、プロフィール写真などの情報を表示します。
多分それは技術的にそれを処理する適切な方法ではありませんが、私にとって最も単純で最も合理的な解決策は、クラスを作成してレイアウトにインスタンス化することです。それは、それ以外の場合は正しい方法で行うための1回限りの例外です。これがレイアウトよりも多く行われている場合は、自分の作業を真剣に考え直して、プロジェクトをさらに進める前にいくつかのチュートリアルを読む必要があります。
public class MyLayoutModel {
public User CurrentUser {
get {
.. get the current user ..
}
}
}
次に、ビューで
@{
// Or get if from your DI container
var myLayoutModel = new MyLayoutModel();
}
.netコアでは、それをスキップして依存性注入を使用することもできます。
@inject My.Namespace.IMyLayoutModel myLayoutModel
それは一種の怪しげなそれらの領域の1つです。しかし、私がここで見ている非常に複雑な代替案を考えると、実用性の名の下に作ることは大丈夫な例外以上のものだと思います。特に、それをシンプルに保ち、重いロジック(本当にあるべきではないと主張しますが、要件は異なります)が、それが属する別のクラス/レイヤーにあることを確認する場合。基本的にビューを1つだけにするために、すべてのコントローラーまたはモデルを汚染するよりも確かに優れています。
アーカイブするには別の方法があります。
ではBaseController
クラスインスタンスのようなモデルクラスを返すメソッドを作成します。
public MenuPageModel GetTopMenu() { var m = new MenuPageModel(); // populate your model here return m; }
Layout
ページでそのメソッドを呼び出すことができますGetTopMenu()
@using GJob.Controllers <header class="header-wrapper border-bottom border-secondary"> <div class="sticky-header" id="appTopMenu"> @{ var menuPageModel = ((BaseController)this.ViewContext.Controller).GetTopMenu(); } @Html.Partial("_TopMainMenu", menuPageModel) </div> </header>
モデルがオブジェクトのコレクション(またはおそらく単一のオブジェクト)であるとしましょう。モデルのオブジェクトごとに、次の操作を実行します。
1)表示するオブジェクトをViewBagに配置します。例えば:
ViewBag.YourObject = yourObject;
2)オブジェクトのクラス定義を含む_Layout.cshtmlの上部にusingステートメントを追加します。例えば:
@using YourApplication.YourClasses;
3)_LayoutでyourObjectを参照するときにキャストします。(2)でやったことから、キャストを適用できます。
public interface IContainsMyModel
{
ViewModel Model { get; }
}
public class ViewModel : IContainsMyModel
{
public string MyProperty { set; get; }
public ViewModel Model { get { return this; } }
}
public class Composition : IContainsMyModel
{
public ViewModel ViewModel { get; set; }
}
レイアウトでIContainsMyModelを使用します。
解決しました。インターフェースのルール。