简体   繁体   English

如何将倍数和选择性模型传递到MVC剃刀局部视图中?

[英]How to pass multiples and selective Model into MVC razor Partial View?

This is pretty basic but stumbling block on picking up MVC (coming from Web Forms of course)! 这是很基本的,但成为获取MVC的绊脚石(当然来自Web窗体)!

If a _Layout.cshtml has an optional sidebar as a Partial View, how do you get the Controller to pass the ViewModel to it (say, BlogPosts ) without having to include it on all of the Controller's Page / View calls? 如果_Layout.cshtml具有可选的侧边栏作为部分视图,那么如何使Controller传递ViewModel到它(例如BlogPosts ),而不必将其包含在Controller的所有Page / View调用中?

I appreciate the Controllers are where we need to construct Models (not inside Views, Partial or otherwise) and that any Partial View will inherit the Model from its parent (handy). 我理解控制器是我们需要构造模型的地方(不是在View内部,Partial或其他地方),并且任何Partial View都会从其父级(方便)继承Model。 But sometimes the parent page has its own ViewModel (eg. SearchResults ) - and although I could turn it around by passing the sidebar BlogPosts into every View and only adding the the SearchResults for that page, am still stuck with same problem - how to selectively pass potential and multiple Models into parent and partial Views. 但是有时父页面拥有自己的ViewModel (例如SearchResults )-尽管我可以通过将侧边栏BlogPosts传递到每个View中并仅添加该页面的SearchResults来解决它,但仍然存在相同的问题-如何选择性地将潜在的多个模型传递给父视图和部分视图。

So we could put any additional Models in the ViewBag and then pull them out in any Partials, and this maybe the best solution, but seems messy (and not sure if they'd remain strongly typed). 因此,我们可以将任何其他模型放入ViewBag ,然后将其拉到任何Partials中,这也许是最好的解决方案,但看起来很混乱(并且不确定它们是否保持强类型)。 Or is the solution to use an additional Partial View Controller? 还是使用额外的Partial View Controller的解决方案? In which case how you do it, because I get a null Object on the foreach in _DefaultSideBar1.cshtml and debug shows that the additional _DefaultSideBar1() is not running at all (so not surprising it's model doesn't get injected): 在这种情况下,您如何执行此操作,因为我在_DefaultSideBar1.cshtmlforeach上获取了一个空对象,并且调试显示additional _DefaultSideBar1()根本没有运行(因此,不会注入模型就不足为奇了):

Current example route in HomeController.cs : HomeController.cs当前示例路由:

[HttpGet]
    public ActionResult SearchResults(string searchText)
    {
        ViewBag.Title = "Search Results";
        List<WebResult> searchData = new List<WebResult>();
        // generate searchData etc...
        return View(searchData);
    }

Current SearchResults.cshtml (which uses a _Layout.cshtml ): 当前SearchResults.cshtml (使用_Layout.cshtml ):

  @model IEnumerable<Bing.WebResult>
    // ... etc etc....
    @section DefaultSidebar1
    {
        @Html.Partial("_DefaultSidebar1")
    }

Anticipated additional current controller for sidebar which loads but not overridden in controller so with null Object Ref: 侧栏的预期附加电流控制器将加载但不会在控制器中被覆盖,因此对象参考为空:

 [HttpGet]
    public ActionResult _DefaultSideBar1()
    {
        return View(db.BlogPosts.ToList());
    }

Current _DefaultSideBar1.cshtml : Current _DefaultSideBar1.cshtml

  @model IEnumerable<Proj.MVC.SPQ.DataEntities.BlogPost>
    <ul>
        @foreach (var item in Model)
        {
            <li>@Html.ActionLink(item.Title, "Details", new { id=item.ID })</li>
        }
    </ul>

This call 这个电话

@Html.Partial("_DefaultSidebar1")

renders the view with the specified name and with no model (or rather with null for a model). 使用指定的名称渲染视图,并且不使用模型(或者对于模型使用null )。 That is why you get null reference. 这就是为什么您获得空引用。 If you want to render it and have some model available, the correct way to call it is 如果要渲染它并提供一些模型,正确的调用方法是

@Html.Partial("_DefaultSidebar1", theModel)

Of course that assumes the model is available on the parent view, most likely as a part of parent view's model. 当然,假设该模型在父视图中可用,很可能是父视图模型的一部分。

If you, on the other hand, would like to render part of a view a results of some action execution, you can use this: 另一方面,如果您想通过执行某项操作的结果来呈现视图的一部分,则可以使用以下方法:

@Html.RenderAction("_DefaultSidebar1", "ControllerName")

of course ControllerName is optional here. 当然, ControllerName在这里是可选的。 This will call your _DefaultSidebar1 action, rather than just view, and render what result this action produces. 这将调用_DefaultSidebar1动作,而不仅仅是查看,并呈现此动作产生的结果。

Don't get stuck thinking your controller needs to be a work horse for everything. 不要认为您的控制器需要成为一切工作的主力。

Remember what we're doing here; 记住我们在这里做什么; building an HTML page. 建立HTML页面。 A rendered HTML page can have multiple < form > elements. 呈现的HTML页面可以具有多个<form>元素。 With CSS, they can be all over the place...if you wanted that. 使用CSS,它们可以无处不在...如果您需要的话。

Each partial view can have it's own: 每个局部视图都可以拥有自己的视图:

@using (Html.BeginForm("action", "controller", new { routeValue = Model.Id }, FormMethod.Get|FormMethod.Post))

Therefor, separate the concerns of each area of your HTML page into different controllers that understand that data. 因此,将HTML页面的每个区域的关注点分为可理解该数据的不同控制器。

One might be: 一种可能是:

public class ClientController : Controller

Another might be 另一个可能是

public class AddressController : Controller

or even the very important... 甚至是非常重要的...

public class WaffleController : Controller

You might want to have children, and I can't help you there, but your objects might want children, so you just pass that portion of the model to a partial view only concerned with that. 您可能想要孩子,而我在那儿无能为力,但是您的对象可能想要孩子,因此您只需将模型的该部分传递给仅与之相关的局部视图。

I have a page with partial views and view components that display multiple models in one HTML page. 我有一个包含部分视图和视图组件的页面,这些视图在一个HTML页面中显示多个模型。 All are focused on the data they know and each are plug and play - they each load their own JS and asynchronously get the updates they need in response to user input, not affecting a whole page refresh. 所有这些都集中在他们知道的数据上,并且都是即插即用的-它们各自加载自己的JS,并响应用户输入而异步获取所需的更新,而不影响整个页面的刷新。

Each view has it's own JS file for it's own work. 每个视图都有自己的JS文件来完成自己的工作。

for example, my address controller always autofills the fields for the user to help them: 例如,我的地址控制器总是自动填充字段供用户使用,以帮助他们:

$(function() {

var urlGeoIeoip = "http://ip-api.com/json/?callback=?";

$.ajax({
    url: urlGeoIeoip,
    type: "GET",
    dataType: "json",
    timeout: 5000,
    success: function (geoipdata) {

        $("#Address_City").data("kendoComboBox").value(geoipdata.city);
        $("#Address_State").data("kendoComboBox").value(geoipdata.regionName);
        $("#Address_Country").data("kendoComboBox").value(geoipdata.country);

    }
}).fail(function(xhr, status) {
    if (status === "timeout") {
        // log timeout here
    }
});
});

But note that you can call your controller with the URL as well: 但是请注意,您也可以使用URL调用控制器:

   url: 'Address/Validate',

And submit the form like this: 并提交如下形式:

   data: $form.serialize()

And return json data to work with directly in JS by returning JsonResult: 并通过返回JsonResult返回json数据以直接在JS中使用:

public class AddressController : MyBaseController
{
    public JsonResult Validate(Address model)
    {
         //validate logic!      
         return Json(model, JsonRequestBehavior.AllowGet);
    }
}

To do that, you'll need a helper for the JS bundle loader for a partial view: 为此,您需要一个用于JS bundle加载器的帮助程序以获取部分视图:

public static class ScriptBundleManager
{

    private const string Key = "__ScriptBundleManager__";

    /// <summary>
    /// Call this method from your partials and register your script bundle.
    /// </summary>
    public static void Register(this HtmlHelper htmlHelper, string scriptBundleName)
    {
        //using a HashSet to avoid duplicate scripts.
        var set = htmlHelper.ViewContext.HttpContext.Items[Key] as HashSet<string>;
        if (set == null)
        {
            set = new HashSet<string>();
            htmlHelper.ViewContext.HttpContext.Items[Key] = set;
        }

        if (!set.Contains(scriptBundleName))
            set.Add(scriptBundleName);
    }

    /// <summary>
    /// In the bottom of your HTML document, most likely in the Layout file call this method.
    /// </summary>
    public static IHtmlString RenderScripts(this HtmlHelper htmlHelper)
    {
        var set = htmlHelper.ViewContext.HttpContext.Items[Key] as HashSet<string>;

        return set != null ? Scripts.RenderFormat("<script type=\"text/javascript\" src=\"{0}\"></script>", set.ToArray()) : MvcHtmlString.Empty;
    }


}

I have this in the App_Code directory 我在App_Code目录中有这个

I call it like: 我这样称呼它:

@Html.RenderScripts()

in my _Layout.cshtml 在我的_Layout.cshtml中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM