can someone tell me what I'm doing wrong? :-)
I have this simple query:
var sample = from training in _db.Trainings
where training.InstructorID == 10
select new { Something = training.Instructor.UserName };
And I pass this to ViewBag.
ViewBag.Sample = sample;
Then I want to access it in my view like this:
#foreach (var item in ViewBag.Sample) {
#item.Something
}
And I get error message 'object' does not contain a definition for 'Something'. If I put there just #item, I get result { Something = SomeUserName }
Thanks for help.
This cannot be done. ViewBag is dynamic and the problem is that the anonymous type is generated as internal. I would recommend you using a view model:
public class Instructor
{
public string Name { get; set; }
}
and then:
public ActionResult Index()
{
var mdoel = from training in _db.Trainings
where training.InstructorID == 10
select new Instructor {
Name = training.Instructor.UserName
};
return View(model);
}
and in the view:
#model IEnumerable<Instructor>
#foreach (var item in ViewBag.Sample) {
#item.Something
}
If you want to send in ViewData For example and don't want to send in model
you could use the same could as in the upper answer
and in the Controller
enter code here
ViewData[Instractor] = from training in _db.Trainings
where training.InstructorID == 10
select new Instructor {
Name = training.Instructor.UserName
};
and in the view you need to cast this to
`IEnumerable<Instructor>`
but to do this you should use
#model IEnumerable<Instructor>
Then you could do something like this
IEnumerable<instructors> Instructors =(IEnumerable<Instructor>)ViewData[Instractor];
then go with foreach
#foreach (var item in Instructors ) {
#item.Something
}
Related
Actually i want to integrate paging in my view page and for that I am retrieving data from below code and I am passing this code from controller to view but any how I am facing issue as
var model = (from sr in db.StudentRequests
join c in db.Classes
on sr.ClassId equals c.ClassId
select new { sr.StudentRequestId,c.ClassName,sr.CreatedOn,sr.Location,sr.PaymentMethod }).ToList().ToPagedList(page ?? 1, 1);
return View(model);
and I am getting issue as
Type : InvalidOperationException
Message : The model item passed into the dictionary is of type 'PagedList.PagedList`1[<>f__AnonymousType3`5[System.Int32,System.String,System.Nullable`1[System.DateTime],System.String,System.String]]', but this dictionary requires a model item of type 'PagedList.IPagedList`1[Student_Tutor.Models.StudentRequest]'.
Source : System.Web.Mvc
My view side is as
#using PagedList;
#using PagedList.Mvc;
#model IPagedList<Student_Tutor.Models.StudentRequest>
#if (ViewBag.StudentRequest != null)
{
var StudentRequestId = (int)Model.First().StudentRequestId;// Here I am able to get the StudentRequestId
var StudentRequestTimecount = StudentRequestTime.Where(d => d.StudentRequestId == StudentRequestId).ToList();
var TutorStudentRequestcount = TutorStudentRequest.Where(d => d.StudentRequestId == StudentRequestId).ToList();
#Html.Displayfor(model => model.First().StudentRequestId)// here only text is displaying as StudentRequestId
#Html.Displayfor(Model => Model.First().CreatedOn)//here only text is diplaying as created on
}
please expalin why I am getting this error?
Update 1
var model = (from sr in db.StudentRequests
join c in db.Classes
on sr.ClassId equals c.ClassId
select new Studentvm{ StudentRequestId = sr.StudentRequestId,ClassName= c.ClassName,
CreatedOn =Convert.ToDateTime(sr.CreatedOn),Location= sr.Location,PaymentMethod= sr.PaymentMethod })
.ToList().ToPagedList(page ?? 1, 1);
return View(model);
but I am getting error as
An exception of type 'System.NotSupportedException' occurred in Student_Tutor.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method 'System.DateTime ToDateTime(System.Object)' method, and this method cannot be translated into a store expression.
This part of your LINQ code
select new { sr.StudentRequestId,c.ClassName,sr.CreatedOn,sr.Location,sr.PaymentMethod }
That is creating an annonymous object for each item in the result collection you get from your LINQ query and you are creating a PagedList from that. But your view is strongly typed to PagedList<StudentRequest>
The ideal solution is to create a viewmodel to represent the data needed for this view and use that in the projection part of your LINQ query
public class StudentVm
{
public int StudentRequestId { set;get;}
public string ClassName { set;get;}
public DateTime CreatedOn { set;get;}
public string Location { set;get;}
}
Now use this view model for your projection
select new StudentVm { StudentRequestId = sr.StudentRequestId,
ClassName= c.ClassName,
Location = sr.Location,
CreatedOn = sr.CreatedOn }
And make sure your view is not strongly typed to PagedList<StudentVm>
#using PagedList;
#model PagedList<YourNamespace.StudentVm>
<table>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(a=> item.ClassName)</td>
<td>#Html.DisplayFor(a=> item.Location)</td>
<td>#Html.DisplayFor(a=> item.StudentRequestId)</td>
<td>#Html.DisplayFor(a=> item.CreatedOn)</td>
</tr>
}
</table>
Also, from your question, you are not really using the PagedList. To pass just a list of items, you do not need to convert that to PagedList<T> . You can simply send a List<StudentVm> from action method and change your view to be strongly typed to do that. Use PagedList if you are really using it (for paging)
This question already has answers here:
Dynamic Anonymous type in Razor causes RuntimeBinderException
(12 answers)
Closed 6 years ago.
I'm trying to pass dynamic results to View from Controller, method ShowColor returns dynamic results. In View I try to loop through the collection but I'm getting error
'object' does not contain a definition for 'ColorID'.
I have the following code in Controller and View
public class myColor
{
public int ID { get; set; }
public string Name { get; set; }
public string Like { get; set; }
}
public dynamic ShowColor()
{
IList<myColor> color = new List<myColor>();
color.Add(new myColor { ID = 1, Name = "Red", Like = "***" });
color.Add(new myColor { ID = 2, Name = "Green", Like = "*****" });
color.Add(new myColor { ID = 3, Name = "Blue", Like = "**" });
color.Add(new myColor { ID = 4, Name = "Yellow", Like = "*" });
var select = (from c in color
select new
{
ColorID = c.ID,
ColorName = c.Name
}).ToList();
return select;
}
public ActionResult DBDynamic()
{
return View(ShowColor());
}
View
#model dynamic
#{
ViewBag.Title = "DBDynamic";
}
<h2>DBDynamic</h2>
<p>
<ul>
#foreach (var m in Model)
{
<li> #m.ColorID</li>
}
</ul>
</p>
Found the solution here and a nice blog here:
public static ExpandoObject ToExpando(this object anonymousObject)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(anonymousObject))
{
var obj = propertyDescriptor.GetValue(anonymousObject);
expando.Add(propertyDescriptor.Name, obj);
}
return (ExpandoObject)expando;
}
And call it like this
var select = (from c in color
select new
{
ColorID = c.ID,
ColorName = c.Name
})
.AsEnumerable()
.Select(x => x.ToExpando());
return View(select);
An anonymous object is not the same thing as a dynamic. If you want to use it like a dynamic then cast it to that:
#foreach (dynamic m in Model)
However, dynamics are best avoided if at all possible. You lose all compile-time checking and even intellisense. You won't know if you fat-fingered a property name until runtime or even if you've accidentally used the wrong type of thing the wrong way until runtime. If something is broken, you want to know about it at compile-time, not when it's already live and affecting users, when you may not even know that an error has occurred unless a user notifies you. That's a horrible situation for your app to be in.
Long and short, use strong types. If you want something with properties, ColorID and ColorName, create a view model with those properties and select your query into instances of that type. Then, everything will be nice and strongly-typed and you'll know well in advance if there's some error or problem with your code.
I am trying to populate a Kendo mvcGrid and I keep getting the error An item with the same key has already been added.
I have seen elsewhere that duplicate model properties is the likeliest source of the problem but I have no duplicate properties in my model. I've even simplified everything to just a basic mock up to eliminate as many possible variables as possible..and I cant get the grid to load data.
I've tried it as a Html.Partial where its not loaded initially because of a empty model and then loading it through jquery...Ive tried with passing in am empty model so that the grid will load initially without data and then doing a datasource refresh...no luck there either. Basically as soon as I try to add content to the grid with a populated model I get the error and no data is loaded.
Been fighting this issue for 2 days now and had no luck. Ill post my code here maybe someone else can see what I'm missing.
One variable that cant change is the grid resides on a partial view with a model different from its parent view.
in the parent view I have tried both
<div id ="columnkgrid">#{Html.RenderPartial("Columns", new TestFieldIssue.Models.FieldListModel());}</div>
and
<div id="columnkgrid">#Html.Partial("Columns", new TestFieldIssue.Models.FieldListModel())</div>
either way will succeed in posting a grid with no data..it has no data yet because its populated by the selection of a value in a dropdown list.
so as to not over complicate the sample I've just set a hard coded value in the jquery function I have been using to refresh the grid.
function loadgrid() {
var grid = $("#grid").data("kendoGrid");
var val = 1;
grid.dataSource.read({ table_pk: val });
grid.refresh();
}
the grid code in the partial once again kept it simple without any bells and whistles just to test.
#(Html.Kendo().Grid(Model.fields)
.DataSource(data => data
.Ajax()
.Model(model => model.Id(m => m.field_pk))
.Read(r => r.Action("Columns","Home"))
)
.Name("grid")
.Columns(c =>
{
c.Bound(m => m.field_name).Title("Field Name").Width(100);
})
)
and the controller methods loading some mock data
public ActionResult Columns(int? table_pk)
{
FieldListModel model;
if (table_pk == null)
{
model = GetEmptyColumns();
}
else
{
model = GetColumns();
}
return PartialView("Columns", model);
}
public FieldListModel GetColumns()
{
FieldListModel model = new FieldListModel();
model.fields = new List<FieldModel>();
model.fields.Add(new FieldModel { field_name = "field1", field_pk = 1 });
model.fields.Add(new FieldModel { field_name = "field2", field_pk = 2 });
model.fields.Add(new FieldModel { field_name = "field3", field_pk = 3 });
return model;
}
public FieldListModel GetEmptyColumns()
{
FieldListModel model = new FieldListModel();
model.fields = new List<FieldModel>();
model.fields.Add(new FieldModel { field_name = "", field_pk = 0 });
return model;
}
and a very simple Model
public class FieldListModel
{
public List<FieldModel> fields { get; set; }
}
public class FieldModel
{
public int field_pk { get; set; }
public string field_name { get; set; }
}
I made few changes to run your code (correct version of Kendo and JQuery). May be those related to setup at my machine. I was able to reproduce the problem.
Then I changed the action code and was able to see the values populated in Grid:
public ActionResult Columns(int? table_pk, [DataSourceRequest] DataSourceRequest request)
{
FieldListModel model;
if (table_pk == null)
{
model = GetEmptyColumns();
}
else
{
model = GetColumns();
}
return Json(model.fields.ToDataSourceResult(request));
}
The change is accepting an additional parameter in action method of type DataSourceRequest. The Kendo grid wraps request in this object to specify sorting and paging information. The grid itself gets updated with data wrapped under DataSourceRequest object (note in return statement). More information here.
I have ASP.NET MVC 4 application with one view model class and about 20 views representing this view model. This views differs only by fields which user can edit. I want to merge all that views to one and define list of properties available to editing in strongly-typed manner. Ideally, I want something like this:
// Action
public ActionResult EditAsEngineer(int id)
{
//...
viewModel.PropertiesToChange = new List<???>()
{
v => v.LotNumber,
v => v.ShippingDate,
v => v.Commentary
};
return View(viewModel);
}
// View
if (#Model.PropertiesToChange.Contains(v => v.LotNumber)
{
#Html.TextBoxFor(m => m.LotNumber)
}
else
{
#Model.LotNumber
}
Is it possible to do something like this? Or is there a better solution?
Thank you.
Why note something like this (its pseudo code)
public class Prop{
string PropertyName {get;set;}
bool PropertyEditable {get;set;}
}
public ActionResult EditAsEngineer(int id)
{
viewModel.PropertiesToChange = new List<Prop>()
{
new Prop{PropertyName = LotNumber, PropertyEditable = true}
};
return View(viewModel);
}
#foreach (var pin Model.PropertiesToChange)
{
if(p.PropertyEditable){
#Html.TextBoxFor(p)
}else{
#Html.DisplayFor(p)
}
}
This will solve HALF of your problem. You will also need to create a IEqualityComparer<Expression> for your code to work (the default is to check for ref-equals).
return from p in typeof(T).GetProperties()
let param = System.Linq.Expressions.Expression.Parameter(typeof(T), "x")
let propExp = System.Linq.Expressions.Expression.Property(param, p)
let cast = System.Linq.Expressions.Expression.Convert(propExp, typeof(object))
let displayAttribute = p.CustomAttributes.OfType<System.ComponentModel.DataAnnotations.DisplayAttribute>()
.Select(x => x.Order).DefaultIfEmpty(int.MaxValue).FirstOrDefault()
orderby displayAttribute
select System.Linq.Expressions.Expression.Lambda<Func<T, object>>(cast, new [] {param});
This will list out ALL the properties for T. You would also probabily want to use Expression<Func<T, object>> as the type for defining your list of properties.
This will allow you to create a generic view over all properties.
Also you will want to wrap this in some kind of a cache, as this code is SLOW.
I access data with:
public ActionResult Index()
{
//IEnumerable<ChatLogs> c = from p in db.ChatLogs select p;
//return View(c);
using (var db = new ChatLogContext())
{
var list = db.ChatLogs.ToList();
return View(list);
}
}
I would like to know how to save this collection of data inside of TextArea in View? When we used webforms we could just textBox.Text = textBox.Text + "some data from database";
View:
#model IEnumerable<Chat.Models.ChatLogs>
#Html.TextArea("chatScreen", new { #Class = "chatScreen" })
Thank you.
I'd suggest that you create a view model. For example:
class ChatLogsViewModel
{
public string LogListString { get; set; }
}
Pass that to the view, instead of passing the raw list:
var list = db.ChatLogs.ToList();
var vm = new ChatLogsViewModel { LogListString = /* convert list to single string here */ };
return View(vm);
And in the view, just do something like this:
#model Your.Namespace.ChatLogsViewModel
#Html.TextAreaFor(model => model.LogListString)
Using view models will make your life easier as soon as you decide that you want to pass more information to the view than what a single domain model can carry.
In you .cshtml view, you can access data using #Model
Now, since you have a list, I'd recommend you join it and then assign it to TextArea like
#{var strList = string.Join(" ", Model)}
#Html.TextArea("myTextArea",strList)