代码之家  ›  专栏  ›  技术社区  ›  SiberianGuy

ASP.NET MVC Razor将模型传递到布局

  •  85
  • SiberianGuy  · 技术社区  · 14 年前

    我看到的是一个字符串布局属性。但是,如何才能将模型显式传递到布局?

    10 回复  |  直到 14 年前
        1
  •  66
  •   Mattias Jakobsson    14 年前

    如果你有这个问题,看起来你的视图模型有点错误。

    就我个人而言,我从来不打版面。但是,如果您想这样做,您应该有一个基本的viewmodel,您的其他viewmodel继承自该基本viewmodel,并将您的布局键入到该基本viewmodel,然后您将页面分页到特定的一次。

        2
  •  75
  •   BlackjacketMack    8 年前
    1. 向您的控制器(或基本控制器)添加一个名为MainLayoutViewModel(或其他)的属性,该属性具有您想要使用的任何类型。
    2. 在控制器(或基本控制器)的构造函数中,实例化类型并将其设置为属性。
    3. 在布局页中,将该属性转换为类型。

    例子: 控制器:

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

    我喜欢这种方法,因为它是控制布局的控制器,而单独的页面视图模型仍然与布局无关。


    在第一次调用每个操作时,Mvc Core似乎会清除ViewData/ViewBag的内容。这意味着在构造函数中分配ViewData不起作用。但是,使用 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;
                }
            }
        }
    
        3
  •  26
  •   Yakir Manor    9 年前

    这是非常基本的东西,你需要做的就是创建一个基本视图模型,并确保所有!我是认真的!将使用该布局的视图将接收使用该基础模型的视图!

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

    @model Models.SomeViewModel
    
    @{
      ViewBag.Title = "Title";
      Layout = "~/Views/Shared/_Layout.cshtml";
    }
    
    <div class="row">
    

    我不同意将模型传递到布局是一个错误,可以传递一些用户信息,并且可以在控制器继承链中填充数据,因此只需要一个实现。

    但对于基本用户来说,这将起到关键作用

        4
  •  19
  •   Oskar Sjöberg    7 年前

    一个常见的解决方案是创建一个基本视图模型,该模型包含布局文件中使用的属性,然后从基本模型继承到各个页面上使用的模型。

    这种方法的问题是,您现在已经将自己锁定在模型只能从另一个类继承的问题中,并且您的解决方案可能是这样的,您无论如何都不能在您想要的模型上使用继承。

    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>
    

    在页面上,您可以使用如下通用布局模型:

    @model LayoutModel<Customer>
    @{
        var customer = Model.PageModel;
    }
    
    <p>Customer name: @customer.Name</p>
    

    public ActionResult Page()
    {
        return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
    }
    
        5
  •  11
  •   Arya Sh    9 年前

    为什么不添加一个新的部分视图,让我自己的特定控制器将所需的模型传递给部分视图,最后使用Render Partial或RenderAction在Layout.cshtml上呈现所提到的部分视图?

        6
  •  3
  •   LazZiya    7 年前

    旧问题,但仅提及MVC5开发人员的解决方案,您可以使用 Model

    这个 模型 视图和布局中的属性与 ViewDataDictionary 对象,因此无需执行任何额外工作即可将模型传递到布局页,也无需声明 @model MyModelName 在布局中。

    @Model.XXX 在布局中,不会显示intelliSense上下文菜单,因为 模型 这是一个动态对象,就像 ViewBag .

        7
  •  1
  •   computrius    7 年前

    public class MyLayoutModel {
        public User CurrentUser {
            get {
                .. get the current user ..
            }
        }
    }
    

    然后在视野中

    @{
        // Or get if from your DI container
        var myLayoutModel = new MyLayoutModel();
    }
    

    在.net core中,您甚至可以跳过它并使用依赖注入。

    @inject My.Namespace.IMyLayoutModel myLayoutModel
    

    这是一个有点阴暗的地方。但鉴于我在这里看到的极其复杂的替代方案,我认为这不仅仅是一个可以以实用性的名义提出的例外。尤其是如果你确保它保持简单,并确保任何繁重的逻辑(我认为确实不应该有任何逻辑,但需求不同)都在它所属的另一个类/层中。这当然比仅仅为了一个视图而污染所有控制器或模型要好。。

        8
  •  0
  •   HappyPawn8    8 年前

    1) 将要显示的对象放在ViewBag中。例如:

      ViewBag.YourObject = yourObject;
    

    2) 在包含对象类定义的_Layout.cshtml顶部添加using语句。例如:

    @使用你的应用程序;

        9
  •  -3
  •   Will    9 年前
    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。

    解决了的。接口规则。

        10
  •  -6
  •   Martin Fabik    14 年前

    @model IList<Model.User>
    
    @{
        Layout="~/Views/Shared/SiteLayout.cshtml";
    }
    

    阅读更多关于新的 @model