asp.net-mvc 使用模型和 ViewData 项创建 ViewDataDictionary 的简写?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/607985/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 23:22:58  来源:igfitidea点击:

Shorthand for creating a ViewDataDictionary with both a model and ViewData items?

asp.net-mvcrenderpartial

提问by patridge

Is there any way to create a ViewDataDictionarywith a model and additional properties with a single line of code. I am trying to make a RenderPartialcall to a strongly-typed view while assembling both the model and some extra display configuration properties without explicitly assembling the ViewDataDictionary across multiple lines. It seems like it would be possible given the RenderPartialoverload taking both a model objectand a ViewDataDictionarybut it looks like it simply ignores the ViewDataDictionarywhenever they are both populated.

有什么方法可以ViewDataDictionary用一行代码创建一个模型和附加属性。我正在尝试RenderPartial调用强类型视图,同时组装模型和一些额外的显示配置属性,而无需跨多行显式组装 ViewDataDictionary。RenderPartial考虑到同时采用模型object和 a的重载,这似乎是可能的,ViewDataDictionary但看起来它只是忽略了ViewDataDictionary当它们都被填充时。

// FAIL: This will result in ViewData being a ViewDataDictionary
// where Model = MyModelObject and there are no other parameters available.
this.Html.RenderPartial("SomePartialView", MyModelObject, new ViewDataDictionary(new { SomeDisplayParameter = true }));

I found someone else with the same problem, but their solution is the same multi-line concept I found: create a discrete ViewDataDictionarywith the model, add the new parameter(s) and use it in the RenderPartialcall.

我发现其他人有同样的问题,但他们的解决方案与我发现的多线概念相同:ViewDataDictionary使用模型创建一个离散的模型,添加新参数并在RenderPartial调用中使用它。

var SomeViewData = new ViewDataDictionary(MyModelObject);
SomeViewData.Add("SomeDisplayParameter", true);
this.Html.RenderPartial("SomePartialView", SomeViewData);

I can always wrap that logic into a ChainedAddmethod that returns a duplicate dictionary with the new element added but it just seems like I am missing some way of creating a ViewDataDictionarythat would do this for me (and that is a bit more overhead than I was hoping for).

我总是可以将该逻辑包装到一个ChainedAdd方法中,该方法返回一个添加了新元素的重复字典,但似乎我缺少某种方法来创建一个ViewDataDictionary可以为我执行此操作的方法(这比我希望的要多一些开销为了)。

this.Html.RenderPartial("SomePartialView", new ViewDataDictionary(MyModelObject).ChainedAdd("SomeDisplayParameter", true));

public static ViewDataDictionaryExtensions {
    public static ViewDataDictionary ChainedAdd(this ViewDataDictionary source, string key, object value) {
        return source.ChainedAdd(new KeyValuePair<string,object>(key, value));
    }
    public static ViewDataDictionary ChainedAdd(this ViewDataDictionary source, KeyValuePair<string, object> keyAndValue) {
        ViewDataDictionary NewDictionary = new ViewDataDictionary(source);
        NewDictionary.Add(keyAndValue);
        return NewDictionary;
    }
}

As well, trying to assemble a ViewDataDictionarywith an explicit Modeland ModelStatesimply causes a compilation error because the ModelState is read-only.

同时,试图组装一个ViewDataDictionary具有明确ModelModelState简单地会导致编译错误,因为ModelState中是只读的。

// FAIL: Compilation error
this.Html.RenderPartial("SomePartialView", new ViewDataDictionary { Model = MyModelObject, ModelState = new ViewDataDictionary( new { SomeDisplayParameter = true }});

ANSWER(S):It looks like Craig and I ended up finding two separate syntaxes that will get the job done. I am definitely biased in this case, but I like the idea of setting the model first and "decorating" it afterwards.

ANSWER(S):看起来 Craig 和我最终找到了两种不同的语法来完成工作。在这种情况下我肯定有偏见,但我喜欢先设置模型然后“装饰”它的想法。

new ViewDataDictionary(MyModelObject) { { "SomeDisplayParameter", true }, { "SomeOtherParameter", 3 }, { "SomeThirdParameter", "red" } };

new ViewDataDictionary(new ViewDataDictionary() { {"SomeDisplayParameter", true }})
    { Model = MyModelObject };

Of course, I would still be spinning my wheels without his [eventually spot-on] answer, so, circle gets the square.

当然,如果没有他的 [最终准时] 回答,我仍然会转动我的轮子,所以,圆就是正方形。

采纳答案by Craig Stuntz

Use an object initializerand collection initializers:

使用对象初始值设定项和集合初始值设定项:

new ViewDataDictionary(new ViewDataDictionary() { {"SomeDisplayParameter", true }})
    {
        Model = MyModelObject
    }

The inner ViewDataDictionary gets its collection initialized, then this populates the "real" ViewDataDictionary using the constructor overload which takes ViewDataDictionary instead of object. Finally, the object initializer sets the model.

内部 ViewDataDictionary 初始化其集合,然后使用构造函数重载填充“真正的”ViewDataDictionary,该构造函数采用 ViewDataDictionary 而不是对象。最后,对象初始值设定项设置模型。

Then just pass the whole thing without setting MyModelObject separately:

然后只需通过整个事情而不单独设置 MyModelObject :

this.Html.RenderPartial("SomePartialView", null, 
    new ViewDataDictionary(new ViewDataDictionary() { {"SomeDisplayParameter", true }})
        { Model = MyModelObject });

回答by patridge

Using Craig's answer as a starting point--I didn't even know you could combine both a constructor call and an object initializer--I stumbled on this snippetfrom Palermo that leads to a combination that works. He uses some sort of dictionary shorthand that somehow ends up populating the ModelStatewhen consumed by the ViewDataDictionaryobject initializer.

使用 Craig 的回答作为起点——我什至不知道你可以将构造函数调用和对象初始值设定项结合起来——我偶然发现了来自巴勒莫的这个片段,它导致了一个有效的组合。他使用某种字典速记,最终以某种方式填充对象初始值设定项所ModelState消耗的时间ViewDataDictionary

new ViewDataDictionary(MyModelObject) { { "SomeDisplayParameter", true }, { "SomeOtherParameter", 3 }, { "SomeThirdParameter", "red" } };
// Of course, this also works with typed ViewDataDictionary objects (what I ended up using)
new ViewDataDictionary<SomeType>(MyModelObject) { { "SomeDisplayParameter", true }, { "SomeOtherParameter", 3 }, { "SomeThirdParameter", "red" } };

I still don't see how this ends up working given that you cannot set the ModelStateexplicitly in an initializer, but it does seem to maintain both the original model object and the "appended" parameters for the view. There are definitely a number of other permutations of this syntax that do not work--you cannot combine the model with the dictionary in a single object or use object-initializer syntax for the dictionary values--but the above version seems to work.

鉴于您无法ModelState在初始化程序中显式设置 ,我仍然不知道这最终如何工作,但它似乎确实维护了原始模型对象和视图的“附加”参数。这种语法肯定有许多其他排列不起作用——你不能将模型与字典组合在一个对象中,或者对字典值使用对象初始值设定项语法——但上面的版本似乎有效。

回答by Lucifer Sam

I created an extension method on HtmlHelper to copy the property names and values from an anonymous object to a ViewDataDictionary.

我在 HtmlHelper 上创建了一个扩展方法,以将匿名对象中的属性名称和值复制到 ViewDataDictionary。

Sample

样本

Html.RenderPartial("SomePartialView", MyModelObject, new { SomeDisplayParameter = true })

HtmlHelper Extension

HtmlHelper 扩展

public static void RenderPartial(this HtmlHelper htmlHelper, string partialViewName, object model, object viewData)
{
    var vdd = new ViewDataDictionary(model);
    foreach (var property in viewData.GetType().GetProperties()) {
        vdd[property.Name] = property.GetValue(viewData);
    }
    htmlHelper.RenderPartial(partialViewName, vdd);
}

回答by Jeroen van der Meer

This is what worked for me in old style mvc aspx view:

这在旧式 mvc aspx 视图中对我有用:

<% Html.RenderPartial("ContactPartial", Model.ContactFactuur, new ViewDataDictionary(this.ViewData ) { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "Factuur" } }); %>

the thing here is that in the constructor I use the current viewdata "new ViewDataDictionary(this.ViewData)" which is a viewdatadictionary containing the modelstate that I need for the validationmessages.

这里的事情是,在构造函数中,我使用当前的视图数据“new ViewDataDictionary(this.ViewData)”,这是一个包含验证消息所需的模型状态的视图数据字典。

回答by Darrel Lee

I came here with the exact same question.

我带着完全相同的问题来到这里。

What I thought might work was this (pardon the VB Razor syntax)

我认为可能有效的是这个(请原谅 VB Razor 语法)

 @Code Html.RenderPartial("Address", Model.MailingAddress, New ViewDataDictionary(New With {.AddressType = "Mailing Address"}))End Code

But of course you get this error at run-time:

但是当然你会在运行时收到这个错误:

System.InvalidOperationException was unhandled by user code

System.InvalidOperationException 未被用户代码处理

Message=The model item passed into the dictionary is of type 'VB$AnonymousType_1`1[System.String]', but this dictionary requires a model item of type 'ViewModel.Address'.

Message=传递到字典中的模型项的类型为“VB$AnonymousType_1`1[System.String]”,但该字典需要类型为“ViewModel.Address”的模型项。

But what I found, is that what I really wanted was to use was Editor Template anyway.

但我发现,无论如何,我真正想要使用的是编辑器模板。

Instead of RenderPartial use:

而不是 RenderPartial 使用:

@Html.EditorFor(Function(model) model.MailingAddress, "Address",  New With {.AddressType = "Mailing Address"})

An editor template is just a partial view that lives

编辑器模板只是一个存在的局部视图

~/Views/{Model|Shared}/EditorTemplates/templatename.vbhtml

~/Views/{Model|Shared}/EditorTemplates/templatename.vbhtml

My template for Address is a strongly-typed partial view, but the EditorFor method gives the ability to add additional view data items easily with an anon object.

我的 Address 模板是一个强类型的局部视图,但 EditorFor 方法提供了使用 anon 对象轻松添加其他视图数据项的能力。

In the example above I didn't need to include the template name "Address", since MVC would would look for a template with the same name as the model type.

在上面的示例中,我不需要包含模板名称“Address”,因为 MVC 会寻找与模型类型同名的模板。

You can also override the display template in the same way.

您还可以以相同的方式覆盖显示模板。