J'ai déjà eu ce problème une fois auparavant et je ne l'ai pas résolu. J'ai une liste (générée dans un contrôleur MVC3):
ViewBag.Languages = db.Languages
.Select(x => new { x.Name, x.EnglishName, x.Id })
.ToList();
et sur ma page (Razor) j'essaye de le parcourir:
foreach (var o in ViewBag.Languages)
{
string img = "Lang/" + o.EnglishName + ".png";
@* work *@
}
mais la référence à o.EnglishName
échoue avec l'erreur suivante:
'objet' ne contient pas de définition pour 'EnglishName'
la chose curieuse est que si je tape dans la fenêtre immédiate (pendant le débogage):
o { Name = བོད་སྐད་, EnglishName = Tibetan, Id = 31 } EnglishName: "Tibetan" Id: 31 Name: "བོད་སྐད་"
alors évidemment le champ est là. Quel est mon problème ici?
Vous utilisez un objet anonyme ici:
ViewBag.Languages = db.Languages
.Select(x => new { x.Name, x.EnglishName, x.Id })
.ToList();
Les objets anonymes sont émis sous la forme internal
par le compilateur. Les vues Razor sont automatiquement compilées dans un assembly séparé par le runtime ASP.NET. Cela signifie que vous ne pouvez pas accéder aux objets anonymes générés dans vos contrôleurs.
Donc, pour résoudre votre problème, vous pouvez définir un modèle de vue:
public class LanguageViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string EnglishName { get; set; }
}
puis dans votre contrôleur utilisez ce modèle de vue:
ViewBag.Languages = db.Languages
.Select(x => new LanguageViewModel
{
Name = x.Name,
EnglishName = x.EnglishName,
Id = x.Id
})
.ToList();
Et maintenant que vous avez un modèle de vue, la prochaine amélioration apportée à votre code consiste bien entendu à supprimer cette merde de ViewBag
que j'en ai marre de voir et à utiliser simplement des modèles de vue et une frappe puissante:
public ActionResult Foo()
{
var model = db
.Languages
.Select(x => new LanguageViewModel
{
Name = x.Name,
EnglishName = x.EnglishName,
Id = x.Id
})
.ToList();
return View(model);
}
et bien sûr, vous avez une vue fortement typée:
@model IEnumerable<LanguageViewModel>
@Html.DisplayForModel()
puis définissez le modèle d'affichage correspondant qui sera automatiquement restitué par le moteur ASP.NET MVC pour chaque élément du modèle de vue, de sorte que vous n'ayez même pas besoin d'écrire un seul foreach dans vos vues (~/Views/Shared/DisplayTemplates/LanguageViewModel.cshtml
):
@model LanguageViewModel
... generate the image or whatever you was attempting to do in the first place
Cela me laissait de côté jusqu'à ce que je vérifie mon code et trouve ceci
class AdsViewModel
{
public int Id { get; set; }
public string City { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
public string UserEmail { get; set; }
public string ContactPhone { get; set; }
public string ShortTitle { get; set; }
public string AdUrl { get; set; }
}
Le changer pour:
public class AdsViewModel
Fixe le.
Cela peut arriver aussi si le nom de votre classe ne correspond pas au nom du fichier (je sais que c'est stupide mais cela pourrait vous aider)
Veuillez utiliser ViewData au lieu de ViewBag comme.
ViewData["Lang"] = db.Languages
.Select(x => new { x.Name, x.EnglishName, x.Id })
.ToList();
Ensuite
foreach (var o in (dynamic) ViewData["Lang"])
{
string img = "Lang/" + o.EnglishName + ".png";
@* work *@
}