asp.net MVC RC1 RenderPartial ViewDataDictionary - c#

I'm trying to pass a ViewData object from a master page to a view user control using the ViewDataDictionary.
The problem is the ViewDataDictionary is not returning any values in the view user control whichever way I try it.
The sample code below is using an anonymous object just for demonstration although neither this method or passing a ViewData object works.
Following is the RenderPartial helper method I'm trying to use:
<% Html.RenderPartial("/Views/Project/Projects.ascx", ViewData.Eval("Projects"), new ViewDataDictionary(new { Test = "Mark" })); %>
and in my view user control i do the following:
<%= Html.Encode(ViewData["Test"]) %>
Why does this not return anything?
Thanks for your help.
EDIT:
I'm able to pass and access the strongly typed model without any problems. it's the ViewDataDictionary which I'm trying to use to pass say just a single value outside of the model...

This is the neatest way I've seen to do this:
<% Html.RenderPartial("/Views/Project/Projects.ascx", Model, new ViewDataDictionary{{"key","value"}});%>
It may be a little hackish, but it let's you send the model through AND some extra data.

Don't know if anyone still cares but I used a KeyValuePair for the ViewDataDictionary.
<% Html.RenderPartial("ItemRow", item, new ViewDataDictionary{
new KeyValuePair<string, object>("url", url),
new KeyValuePair<string, object>("count", count),
new KeyValuePair<string, object>("className", className)
}); %>
This way you can write everything in one statement. The KVPs can be accessed in the view by:
<%= ViewData["url"] %>
<%= ViewData["count"] %>
<%= ViewData["className"] %>
While what I passed through the model can be accessed through Model.*

I'm using the RTM version of ASP.Net MVC, but with:
<% Html.RenderPartial("~/Views/Project/Projects.ascx", new ViewDataDictionary(new {Key = "Some value"})); %>
Try the following when referencing the value in your partial view:
<%= ViewData.Eval("Key") %>
That seems to have done the trick for me. It will also work if you just do this:
<% Html.RenderPartial("~/Views/Project/Projects.ascx", new {Key = "Some value"}); %>
Hope this helps.

Have you tried:
<% Html.RenderPartial("~/Views/Project/Projects.ascx", ViewData); %>
Also have you verified ViewData["Test"] is in the ViewData before you are passing it? Also note that when passing your ViewData to a Partial Control that it is important to keep the Model the same.
Nick

In your main view:
<% Html.RenderPartial("~/Views/Project/Projects.ascx", ViewData["Projects"]); %>
Either in you controller or your main view:
ViewData["Test"] = "Mark";
If you don't specify a model or view data dictionary in RenderPartail, it uses the ones from the containing view.

Related

ASP ViewModel from controller (the Model not model => model.FieldName) became null when postback to controller action

I have an mvc aspx page with strongly typed model, it looked like this
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<DeliveryService.ViewModels.DeliveryRequestViewModel>" %>
so when I call a create function, the page shows the initialized data from the view model
but when I submit the form (calling the postback create function)
I got a null exception error like on the line:
<%: Html.DropDownListFor(model => model.FromGroup, Model.LocationList) %>
the error pointed to Model.LocationList
I have another field in the aspx page, but it doesn't triggering null exception, the code looks like this
<%: Html.EditorFor(model => model.Address) %>
Please point my error, why is when I use the Model with capital at the first letter I get a null exception error. Thank you very much
I have an extra question:
<%: Html.EditorFor(model => model.DeliveryRequestNumber, new {#readonly = "readonly"}) %>
what is the correct syntax to create a readonly textbox using editorfor? tried this but, the rendered html code is
<input class="text-box single-line valid" id="DeliveryRequestNumber" name="DeliveryRequestNumber" type="text" value="somevaluegeneratedfrommodel">
1 Why do I get a NRE?
I'm guessing, but your reference to 'PostBack' might mean that you come from a WebForms background. In MVC, controller actions must always return the FULL state required to render the view (e.g. in the ViewModel), even after a POST:
[HttpPost]
ActionResult Create(DeliveryRequestViewModel someModel)
{
// Do something
return View("SomeView", someModel); <-- Remember to pass the ViewModel again
}
2 Re : Model vs model
Please point my error, why is when I use the Model with capital at the first letter I get a null exception error. Thank you very much
Model is an instance of the type of the page's model - DeliveryRequestViewModel in this case. (From Inherits="ViewPage<DeliveryRequestViewModel> of the .aspx, or from #model in razor)
Whereas in this case:
<%: Html.EditorFor(model => model.Address) %>
model is a placeholder variable for a lambda expression which projects the Address property off the variable. Placeholder, because it could be anything, e.g.
Html.EditorFor(foo => foo.Address)
3 Re:Readonly Text Box
This here has some ideas
Also, I guess you could just use Html.DisplayFor if you just want to render the value?

Html.TextBox("Title") inside partial view (.ascx) gets value "Title" from the parent View

In my forum project I have a partial view (.ascx) that is used for adding a new forum post. Forum posts live inside Topics (Categories) and both these tables have a column named Title.
Now the problem is that when I place the partial view on a Topic page, it automatically grabs the Title value from the Topic, thus populating my Title Textbox with the Topic Title. Not ideal!
The code inside the CreatePost.ascx is simply
<label for="Title">Title</label>
<%= Html.TextBox("Title") %>
I've tried changing that to <%= Html.TextBox("Post.Title") %> but then the Textbox value doesn't get posted.
Is this normal behaviour, and is there a way I can get rid of it without clearing it with Javascript?
I've even tried setting a value using the 2nd overload Html.TextBox("Title", "some value") but that just gets overridden.
Please help!
If you are using ASP.NET MVC 2 you should always use strongly typed helpers which will correctly handle binding:
<%= Html.TextBoxFor(x => x.Category.Title) %>
Try the following:
CreatePost.ascx
<label for="Title">Title</label>
<%= Html.TextBox("Title") %>
YourController.cs
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(string Title) {
// do something with Title
return View();
}
Need to make sure CreatePost.ascx is being rendered between
<% using (Html.BeginForm()) { %>....
..
<% Html.RenderPartial("CreatePost.ascx");
..
..
<% } >
in your View.
Hope this helps...
It sounds like the issue is with the code you are using to render the partial view. RenderPartial will be default pass through the model from the parent view, hence the behaviour you are seeing when the Topic title is displayed in the partial. You can override this though - one of the parameter of RenderPartial allow you to pass in a new model.
Something like:
<% Html.RenderPartial("CreatePost.ascx", new Post());%>
to pass in a new model to the partial view (in this case an empty Post).

How to make data available when one Controller's View calls another Controller's View?

Background:
I'm trying to produce dynamically generated Factsheets, where each Factsheet has a number of ContentAreas, and each ContentArea is configured to contain a number of Panels.
I have a FactsheetController, a ContentAreaController, a PanelController and individual panels such as NameAndDate and AssetPanel
FactsheetController produces an Index View which acts as a template to load ContentAreas in to.
This is FactsheetController's Index, where Model contains the configuration data defining which panels are associated with which ContentArea:
<div id="divTop">
<% Html.RenderAction("Top", "ContentArea", Model); %>
</div>
<div id="divLeftColumn">
<% Html.RenderAction("Left", "ContentArea", Model); %>
</div>
<div id="divRightColumn">
<% Html.RenderAction("Right", "ContentArea", Model); %>
</div>
<div id="divBottom">
<% Html.RenderAction("Bottom", "ContentArea", Model); %>
</div>
When the Top action method gets called on ContentAreaController, it passes a list of PanelConfigurations associated with that ContentArea to its PartialView, which is defined as:
<% foreach (ConfiguredFactsheetPanel panel in Model)
{ %>
<% Html.RenderAction(panel.Name, "Panel", panel); %>
<% } %>
This PartialView renders then renders each panel that it is configured to show.
When I'm loading the FactsheetController I need an instance of a Fund object to know which ContentAreas are associated with that particular Factsheet, so I create one based on QueryString data. The thing is, I also need that Fund object in the PanelController because the Fund object contains the data I need to display. That QueryString data doesn't exist in the PanelController, because it only existed in the URL that called FactsheetController.
question:
So my question is, what's the best way for me to make the Fund object I create in FactsheetController to be available in the PanelController
I'd also be interested in hearing anyone's opinion on issues with this initial design.
I wouldn't use query strings like that. I would extend the model object passed to FactsheetController's Index to include the data required in your other partial views and then pass that to the actions with the RenderAction method. So ConfiguredFactsheetPanel would be extended to either contain, or be replaced by a type that contained, the Fund object you require in your partial views.
I suspect that the objects that you are using in your view currently are entities driven by your persistence technology such as NHibernate or Entity Framework. If this is the case you probably won't want to change your entity definitions to satisfy your views and instead create view models.

How to pass data from view to UserControl in ASP.NET MVC?

Say I want to do the simplest of the data passing as follows :
<% For i = 0 To 10%>
<%Html.RenderPartial("MyUserControl")%>
<% Next%>
What I want to do is to pass the variable i as the parameter to the UserControl so that it displays the number inside a, say, bordered div.
How is this possible?
Thanks
<% For i = 0 To 10%>
<%Html.RenderPartial("MyUserControl", i)%>
<% Next%>
The RenderPartial method has an overload that allows you to pass in a (sub)model. To use it most effectively, your UserControl should be strongly typed - in this case to a model of type System.Int32.
To use it in a UserControl:
<%# Control Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<System.Int32>" %>
<div><%= this.Html.Encode(this.Model) %></div>
In this case, this.Model is a System.Int32 instance.
you do not. This stuff must be in the model, suppsedly.
PLease upgrade to MVC v2 ;) get rid of the strings.

Struggling with ASP.NET MVC auto-scaffolder template

I'm trying to write an auto-scaffolder template for Index views. I'd like to be able to pass in a collection of models or view-models (e.g., IQueryable<MyViewModel>) and get back an HTML table that uses the DisplayName attribute for the headings (th elements) and Html.Display(propertyName) for the cells (td elements). Each row should correspond to one item in the collection.
Here's what I have so far:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%
var items = (IQueryable<TestProj.ViewModels.TestViewModel>)Model;
// How do I make this generic?
var properties = items.First().GetMetadata().Properties
.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm));
%>
<table>
<tr>
<%
foreach(var property in properties)
{
%>
<th>
<%= property.DisplayName %>
</th>
<%
}
%>
</tr>
<%
foreach(var item in items)
{
HtmlHelper itemHtml = ????;
// What should I put in place of "????"?
%>
<tr>
<%
foreach(var property in properties)
{
%>
<td>
<%= itemHtml.Display(property.DisplayName) %>
</td>
<%
}
%>
</tr>
<%
}
%>
</table>
Two problems with this:
I'd like it to be generic. So, I'd like to replace var items = (IQueryable<TestProj.ViewModels.TestViewModel>)Model; with var items = (IQueryable<T>)Model; or something to that effect.
A property Html is automatically created for me when the view is created, but this HtmlHelper applies to the whole collection. I need to somehow create an itemHtml object that applies just to the current item in the foreach loop. I'm not sure how to do this, however, because the constructors for HtmlHelper don't take a Model object.
How do I solve these two problems?
Phil Haack to the rescue!
http://haacked.com/archive/2010/05/05/asp-net-mvc-tabular-display-template.aspx
for the geniric IQueryable part, why don't you simply cast it to an IQueryable...
var items = (IQueryable<TestProj.ViewModels.TestViewModel>)Model;
and What is your template for, isn't it almost the same as the default list template when you add a view... If you want to customize it, i think you'd better look for the List.tt template. You could modify that to use Html.Display instead of Html.Encode.
Or you could try using
Html.DisplayFor(o => property.GetValue(item))
I'm not sure if this would work...
Sadly you can't do:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<List<T>>" %>
or even
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<T>" %>
ASP.NET MVC implements a Html.DisplayForModel() as Brad Wilson shows on his blog which does scaffolding for you out of the box. (which I'm sure you know about, mentioning for completeness).
If you look at the MVC 2 RTM Source Code source code and in particular the DefaultDisplayTemplates.cs it's all basically contained in an HTMLHelper as suppose to a View. Perhaps instead of fighting with the auto generated class for the view (as much as I love asp.net mvc the default view rendering engine is a total pain) go with an HTMLHelper extension modelled after how ASP.NET MVC RTM implements scaffolding. I guess this would open the possibility for code reuse some more too (though almost everything is internal).
It would be nice if the ASP.NET MVC scaffolding would allow for a custom template to be passed in to change the html if you're not a fan of the default <div class=\"display-field\"> etcetera. To me this is one of the weak spots of ASP.net MVC (the 'hardcoded' error handling/ scaffolding HTML).
If your not a fan of string building your HTML, your extension could call out to more granular partial views (like ScaffoldCaption.ascx) when your scaffolding HTMLHelper extension has gathered enough information to sufficiently type the granular view.
Have you looked into the MVCContrib Grid? Certainly someone has written an extension method to show all properties by default. If not it shouldn't be difficult.
edit2- I guess don't trust my answers on Sunday. I misread the question before and didn't realize Html.Display() was the MVC2 templated input. (I'm doing some radically different input builders at my shop so I didn't pick up on the name. I just thought Display showed the value.) Anyway, there are two options I see here.
1) Pull the MVC2 source or break out Reflector and write your own method that is not extending HtmlHelper.
2) You can use reflection here to build a new HtmlHelper instance but it's not pretty. (I didn't test this but is should work.)
var modelType = Html.GetType().GetGenericParameters()[0];
var itemHtmlType = typeof(HtmlHelper<>).MakeGenericType(modelType);
var itemHtmlCtor = itemHtmlType.GetConstructor(typeof(ViewContext), typeof(IViewDatacontainer), typeof(RouteCollection));
var itemHtml = itemHtmlCtor.Invoke(Html.ViewContext, Html.ViewDataContainer, Html.RouteCollection);
You'll get an object out of this though so you have to use reflection to invoke itemHtml.Dipslay. I'd recommend going a different route.

Categories

Resources