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

Sib*_*Guy 89 .net c# asp.net-mvc razor

我看到的是字符串布局属性.但是如何将模型明确地传递给布局?

Bla*_*ack 74

  1. 使用您想要使用的任何类型向称为MainLayoutViewModel(或其他)的控制器(或基本控制器)添加属性.
  2. 在控制器(或基本控制器)的构造函数中,实例化类型并将其设置为属性.
  3. 将其设置为ViewData字段(或ViewBag)
  4. 在"布局"页面中,将该属性强制转换为您的类型.

示例:控制器:

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

}
Run Code Online (Sandbox Code Playgroud)

布局页面的示例顶部

@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以在布局页面中引用变量"viewModel",并可以完全访问类型化对象.

我喜欢这种方法,因为它是控制布局的控制器,而单个页面视图模型仍然是布局不可知的.

MVC核心的注释


在第一次调用每个动作时,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;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • @User - TempData使用Session,对我来说总觉得有点笨拙.我的理解是它是"一次性读取",因此一旦你读取它就会从会话中删除它(或者一旦请求结束就将其删除).您可能在Sql Server(或Dynamo Db)中存储会话,因此请考虑您必须序列化MasterLayoutViewModel ...而不是您最想要的.所以基本上,将它设置为ViewData会将它存储在一个灵活的字典中,这符合要求. (2认同)

Mat*_*son 66

如果你有这个问题,似乎你已经模拟了你的viewmodels有点不对劲.

就个人而言,我永远不会打印布局页面.但是如果你想这样做,你应该有一个你的其他视图模型继承的基本视图模型,并将你的布局键入基本视图模型,然后你可以翻页到特定的一次.

  • @eglasius,我使用的解决方案根据我们谈论的内容类型而有所不同.但常见的解决方案是使用RenderAction在布局页面中呈现需要自己数据的部件.我不喜欢键入布局页面的原因是它会强制您始终在所有特定视图模型中继承"基本"视图模型.根据我的经验,这通常不是一个非常好的主意,并且很多时候你会在更改设计时遇到问题(或者需要很长时间). (52认同)
  • "就我个人而言,我永远不会打印布局页面." 为什么?我的意思是,你如何处理所有页面中出现的副动态内容?你是否从视图中跳过控制器?/也许你的意思是从布局中使用RenderAction?(我现在只是看着它) (9认同)
  • 我有2个解决方案:布局的通用模型,所以我可以使用MyLayoutModel <MyViewModel>作为视图模型,只在布局中使用RenderPartial和MyViewModel.或者使用RenderAction为静态缓存部件和动态部件的ajax调用部分渲染页面部分.但我更喜欢第一个解决方案,因为它更适合搜索引擎,并且很容易与ajax更新结合使用. (4认同)
  • 使用遗留代码完成此操作.这是一场噩梦.不要输入您的布局... pleeease! (4认同)
  • 如果我想通过聚合而不是通过继承来包含基本模型,该怎么办?从设计角度看,这是一种完全合法的方式 那我怎么处理布局呢? (2认同)

Yak*_*nor 26

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

public class SomeViewModel : ViewModelBase
{
    public bool ImNotEmpty = true;
}

public class EmptyViewModel : ViewModelBase
{
}

public abstract class ViewModelBase
{
}
Run Code Online (Sandbox Code Playgroud)

在_Layout.cshtml中:

@model Models.ViewModelBase
<!DOCTYPE html>
  <html>
  and so on...
Run Code Online (Sandbox Code Playgroud)

在家庭控制器中的索引(例如)方法中:

    public ActionResult Index()
    {
        var model = new SomeViewModel()
        {
        };
        return View(model);
    }
Run Code Online (Sandbox Code Playgroud)

Index.cshtml:

@model Models.SomeViewModel

@{
  ViewBag.Title = "Title";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<div class="row">
Run Code Online (Sandbox Code Playgroud)

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

显然,为了更高级的目的,您应该考虑使用注入创建自定义静态文本,并在_Layout.cshtml中包含该模型命名空间.

但是对于基本用户来说,这将有所帮助


Osk*_*erg 17

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

这种方法的问题在于,您现在已经将自己锁定在模型只能从其他类继承的问题中,并且您的解决方案可能无法在您想要的模型上使用继承.

我的解决方案也开始使用基本视图模型:

public class LayoutModel
{
    public LayoutModel(string title)
    {
        Title = title;
    }

    public string Title { get;}
}
Run Code Online (Sandbox Code Playgroud)

然后我使用的是LayoutModel的泛型版本,它继承自LayoutModel,如下所示:

public class LayoutModel<T> : LayoutModel
{
    public LayoutModel(T pageModel, string title) : base(title)
    {
        PageModel = pageModel;
    }

    public T PageModel { get; }
}
Run Code Online (Sandbox Code Playgroud)

有了这个解决方案,我就无需在布局模型和模型之间进行继承.

所以现在我可以继续使用Layout.cshtml中的LayoutModel,如下所示:

@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

在页面上,您可以使用通用的LayoutModel,如下所示:

@model LayoutModel<Customer>
@{
    var customer = Model.PageModel;
}

<p>Customer name: @customer.Name</p>
Run Code Online (Sandbox Code Playgroud)

从您的控制器中,您只需返回LayoutModel类型的模型:

public ActionResult Page()
{
    return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}
Run Code Online (Sandbox Code Playgroud)


小智 11

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

我使用此方法显示登录用户的信息,如姓名,个人资料图片等.

  • 你能详细说明吗?我很欣赏一些通过这种技术的博客文章的链接 (2认同)

Laz*_*iya 5

老问题,但只是提一下 MVC5 开发人员的解决方案,您可以使用Model与视图中相同的属性。

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

但请注意,当您@Model.XXX在布局中使用时,智能感知上下文菜单将不会出现,因为这里Model是一个动态对象,就像ViewBag.