Pass multiple list from controller to view - list

I MVC c# application which has model
public class lstSearchCriteria
{
public List<lstCampaign> cmpList { get; set; }
public List<lstAgent> agentList { get; set; }
}
public class lstCampaign
{
public string campaignName { get; set; }
}
public class lstAgent
{
public string agentShortName { get; set; }
public string agentFullName { get; set; }
}
& controller which returns lstSearchCriteria. I need to display lstCampaign & lstAgent in dropdown list.
In view I am doing
#using QAApplication.Models
#model QAApplication.Models.lstSearchCriteria
<select id="lstCampaigns" multiple="multiple">
#foreach (var item in Model.cmpList)
{
<option >#item.campaignName</option>
}
</select>
<div id="divlstAgents">
<select id="lstAgents" multiple="multiple">
#foreach (var item in Model.agentList)
{
<option >#item.agentShortName</option>
}
</select>
</div>
I am getting below error :The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[QAApplication.Models.lstSearchCriteria]', but this dictionary requires a model item of type 'QAApplication.Models.lstSearchCriteria'.
what could be the best way to pass multiple list to view from controller. Thanks in advance

You are passing List<lstSearchCriteria>, While Views expected model lstSearchCriteria only.

Related

UWP - NavigationView with two different Sources

I have an ObservableCollection<Category> binded to a NavigationView, where Category is a custom class that implements INotifyPropertyChanged. I created a DataTemplate to display the element of the collection
<DataTemplate x:Key="CategoryTemplate">
<NavigationViewItem Icon="{Binding Icon}" RightTapped="CategoryItem_RightTapped">
<local:CategoryViewItem CategoryItem="{Binding Mode=TwoWay}"/>
</NavigationViewItem>
</DataTemplate>
Now I want to add some default NavigationViewItem and a NavigationViewItemSeparator at the top of the list with a different DataTemplate keeping the second part "Observable" and "Notifying changes of properties". You can see an example of what I mean in the image below.
For your requirement, you need make MenuItemTemplateSelector for NavigationView. And pass the different DataTemplate base on the data source.
Default NavigationViewItem and NavigationViewItemSeparator Data Model
public class CategoryBase { }
public class DefaultCategory: CategoryBase
{
public string Name { get; set; }
public string Tooltip { get; set; }
public Symbol Glyph { get; set; }
}
public class CustomCategory : CategoryBase
{
public SymbolIcon Icon { get; set; }
public string Title { get; set; }
}
public class Separator : CategoryBase { }
MenuItemTemplateSelector
public class MenuItemTemplateSelector : DataTemplateSelector
{
internal DataTemplate SeparatorTemplate = (DataTemplate)XamlReader.Load(
#"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
<NavigationViewItemSeparator />
</DataTemplate>");
public DataTemplate DefaultItemTemlate { get; set; }
public DataTemplate CustomItemTemlate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
return item is Separator ? SeparatorTemplate : item is CustomCategory ? CustomItemTemlate : DefaultItemTemlate;
}
}
Xaml Code
<Page.Resources>
<local:MenuItemTemplateSelector x:Key="selector">
<local:MenuItemTemplateSelector.DefaultItemTemlate>
<DataTemplate x:DataType="local:DefaultCategory">
<NavigationViewItem Content="{x:Bind Name}">
<NavigationViewItem.Icon>
<SymbolIcon Symbol="{x:Bind Glyph}" />
</NavigationViewItem.Icon>
</NavigationViewItem>
</DataTemplate>
</local:MenuItemTemplateSelector.DefaultItemTemlate>
<local:MenuItemTemplateSelector.CustomItemTemlate>
<DataTemplate>
<NavigationViewItem Icon="{Binding Icon}">
<TextBlock Text="{Binding Title}" />
</NavigationViewItem>
</DataTemplate>
</local:MenuItemTemplateSelector.CustomItemTemlate>
</local:MenuItemTemplateSelector>
</Page.Resources>
<Grid>
<NavigationView
x:Name="nvSample"
MenuItemTemplateSelector="{StaticResource selector}"
MenuItemsSource="{x:Bind Categories, Mode=OneWay}"
/>
<Button Click="Button_Click" Content="AddItem" />
</Grid>
Usage
public MainPage()
{
this.InitializeComponent();
Categories = new ObservableCollection<CategoryBase>();
Categories.Add(new CustomCategory { Title = "This is Titlte", Icon = new SymbolIcon(Symbol.Play) });
}
public ObservableCollection<CategoryBase> Categories { get; }
private void Button_Click(object sender, RoutedEventArgs e)
{
Categories.Insert(0, new Separator());
Categories.Insert(0, new DefaultCategory { Name = "Category 1", Glyph = Symbol.Home, Tooltip = "This is category 1" });
}
You could find the code sample here, and this NavigationView document that you could refer.

How to display foreign key name in list table in Blazor Client Side

I am trying to display a subject name for a course where I saved the subject from a database driven dropdown list in a client-side Blazor app. The value returns as a Guid instead of the subject name. Has anyone accomplished this with Blazor? I couldn't find anything in the Blazor documentation or any tutorials that could solve the issue I'm having. This is in Blazor client-side and I am using Entity Framework Core
This is what my Course model looks like in the Shared project:
public class Course
{
public Guid CourseID { get; set; }
[Required]
public string CourseCode { get; set; }
[Required]
public string CourseName { get; set; }
public string CourseSubject { get; set; }
public string CourseCredits { get; set; }
}
This is what my Subject model looks like in the Shared project:
public class Subject
{
public Guid SubjectID { get; set; }
public string SubjectName { get; set; }
}
This is my CourseData Data Access Model in the Server project:
ApplicationDbContext db = new ApplicationDbContext ();
public IEnumerable<Course> GetAllCourses()
{
try
{
return db.Courses.ToList();
}
catch
{
throw;
}
}
public void AddCourse(Course course)
{
try
{
db.Courses.Add(course);
db.SaveChanges();
}
catch
{
throw;
}
}
This is my SubjectData Data Access Model in the Server project:
ApplicationDbContext db = new ApplicationDbContext ();
public IEnumerable<Subject> GetAllSubjects()
{
try
{
return db.Subjects.ToList();
}
catch
{
throw;
}
}
public void AddSubject(Subject subject)
{
try
{
db.Subjects.Add(subject);
db.SaveChanges();
}
catch
{
throw;
}
}
This is my Course Controller in the Server project:
CourseData objcourse = new CourseData();
[HttpGet]
[Route("api/Courses/Courses")]
public IEnumerable<Course> Index()
{
return objcourse.GetAllCourses();
}
[HttpPost]
[Route("api/Courses/Create")]
public void Create([FromBody] Course course)
{
if (ModelState.IsValid)
objcourse.AddCourse(course);
}
This is how I save the value in my Course creation page in my Client project:
#page "/Courses/Create"
#inject HttpClient Http
#inject Microsoft.AspNetCore.Components.NavigationManager NavigationManager
<h1>Add Course</h1>
<hr />
<div class="row">
<div class="col-md-4">
<div>
<div class="form-group">
<label for="CourseCode" class="control-label">Course Code</label>
<input for="CourseCode" class="form-control" #bind="#course.CourseCode" />
</div>
<div class="form-group">
<label for="CourseName" class="control-label">Course Name</label>
<input for="CourseName" class="form-control" #bind="#course.CourseName" />
</div>
<div class="form-group">
<label for="CourseSubject" class="control-label">Subject</label>
<select class="form-control" #bind="#course.CourseSubject">
<option></option>
#foreach (var subject in subjectList)
{
<option value="#subject.SubjectID">#subject.SubjectName</option>
}
</select>
</div>
<div class="form-group">
<label for="CourseCredits" class="control-label">Course Credits</label>
<input for="CourseCredits" class="form-control" #bind="#course.CourseCredits" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-default" #onclick="#CreateCourse">Save</button>
<button class="btn" #onclick="#cancel">Cancel</button>
</div>
</div>
</div>
</div>
#functions {
List<Subject> subjectList = new List<Subject>();
Course course = new Course();
protected override async Task OnInitializedAsync()
{
subjectList = await Http.GetJsonAsync<List<Subject>>("api/Subjects/Subjects");
}
protected async Task CreateCourse()
{
await Http.SendJsonAsync(HttpMethod.Post, "/api/Courses/Create", course);
NavigationManager.NavigateTo("/Courses/Courses");
}
void cancel()
{
NavigationManager.NavigateTo("/Courses/Courses");
}
}
And finally this is my Courses list page in my Client project where it returns the Guid for the subject name, for which I would like to show the subject name instead of it's Guid:
#page "/Courses/Courses"
#inject HttpClient Http
<h1>Courses</h1>
<p>
Create New
</p>
#if (courseList == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class='table'>
<thead>
<tr>
<th>Course Code</th>
<th>Course Name</th>
<th>Subject</th>
<th>Credits</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
#foreach (var course in courseList)
{
<tr>
<td>#course.CourseCode</td>
<td>#course.CourseName</td>
<td>#course.CourseSubject</td>
<td>#course.CourseCredits</td>
<td>
<a href='/Courses/Edit/#course.CourseID'>Edit</a> |
<a href='/Courses/Delete/#course.CourseID'>Delete</a>
</td>
</tr>
}
</tbody>
</table>
}
#functions {
Course[] courseList;
protected override async Task OnInitializedAsync()
{
courseList = await Http.GetJsonAsync<Course[]>
("/api/Courses/Courses");
}
}
Database Context as requested:
public class ApplicationDbContext : DbContext
{
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Subject> Subjects { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(#"REMOVED-FOR-SECURITY");
}
}
}
Help would be much appreciated.
Other answers are good but let me give you something else to think about...
When writing Blazor apps try to think in terms of components more often than of code.
For example, let's say that the Subjects are static data that doesn't change a lot. So if every time you show a list, or want to build a dropdown for them, you're potentially going to have to make a database call or a SQL JOIN? So my first thought would be to create a lookup cache for GUID-to-Subject-name. And since this is Blazor if it's cached on the client you no longer need to make a database or API call - it's loaded once.
Then, since we're in Blazor, I'd create a <SubjectName> component, e.g.
Subject: <SubjectName Id="#Model.SubjectId" />
The component uses the cache to get the value, it can handle a null value, it can handle an invalid subject ID. You've encapsulated a lot of behaviour and error handling in a single place, and can re-use that every time you need to map an ID to a subject name.
Similarly I'd create a <SubjectDropdown> component to show a list of subjects, again using the cache.
You set CourseSubject with the SubjectID with is a Guid, so you get a Guid.
If you want to display the subject name either, request the subject by its Guid, or return the Subject in your course:
public class Course
{
public Guid CourseID { get; set; }
[Required]
public string CourseCode { get; set; }
[Required]
public string CourseName { get; set; }
public string CourseSubject { get; set; }
public string CourseCredits { get; set; }
public virtual Subject Subject { get; set; }
}
public IEnumerable<Course> GetAllCourses()
{
try
{
return db.Courses
.Include(c => c.Subject)
.ToList();
}
catch
{
throw;
}
...
}
#foreach (var course in courseList)
{
<tr>
<td>#course.CourseCode</td>
<td>#course.CourseName</td>
<td>#course.Subject.SubjectName</td>
<td>#course.CourseCredits</td>
<td>
<a href='/Courses/Edit/#course.CourseID'>Edit</a> |
<a href='/Courses/Delete/#course.CourseID'>Delete</a>
</td>
</tr>
}

MVC custom serialization of List<X> parameter for GET request?

I'm wanting to change a request to be GET instead of POST so users can share the generated URLs.
The current system uses a normal form submit and takes advantage of the automatic serialization between the form submit and the MVC ActionResult for a List of custom objects.
e.g.
<form action="/MyPage">
<input type="hidden" id="MyThings_0__Value" name="MyThings[0].Value">
<input type="hidden" id="MyThings_0__Flag" name="MyThings[0].Flag">
<input type="hidden" id="MyThings_1__Value" name="MyThings[1].Value">
<input type="hidden" id="MyThings_1__Flag" name="MyThings[1].Flag">
</form>
However doing it this way causes the GET string generated to be overly long and complicated. This is bad because the MyThings list can be up to 10 items long.
http://myurl.com/MyPage?MyThings%5B0%5D.Value=ThisIsValue1&MyThings%5B0%5D.Flag=1&MyThings%5B1%5D.Value=ThisIsValue2&MyThings%5B1%5D.Flag=2
I was hoping for the string to appear more user-friendly. Something like:
http://myurl.com/MyPage?MyThings=ThisIsValue1-1,ThisIsValue2-2
Can this be done with custom serialization? And if so, how would I go about implementing it?
My Model and ActionResult:
namespace MyNamespace {
public class MyThing {
public string Value { get; set; }
public int Flag { get; set; }
}
public class Filter {
public string CustomAttribute1 { get; set; }
public string CustomAttribute2 { get; set; }
public string CustomAttribute3 { get; set; }
public List<MyThing> MyThings { get; set; } = new List<MyThing>();
}
public ActionResult MyPage(Filter filter) {
MyModel model = StaticMethod.GetMyModel(filter);
return View(model);
}
}
In the end I decided against using custom URL serialization and used helper methods to convert to string/class backward and forwards within the C# model.
public class Filter {
public string MyThing { get; set; }
public List<MyThingClass> MyThings {
get {
if (this._myThings == null) { // Default to Query string
this._myThings = ToQueryList(this.MyThing);
}
return this._myThings;
}
set {
this.MyThing = ToQueryString(value); // Automatically assign QueryString to serialized QueryItems on set
this._myThings = value;
}
}
private List<MyThingClass> _myThings { get; set; }
public static List<MyThingClass> ToQueryList(string queryString) {
return queryString.Split(',').Select(x => MyThingClass.FromString(x)).ToList();
}
public static string ToQueryString(List<MyThingClass> myThings) {
return string.Join(",", myThings.Select(x => x.ToString()));
}
}
public class MyThingClass {
public string Value { get; set; }
public int Flag { get; set; }
/// <summary>Converts a QueryItem object to a serialized object ready for the QueryString.</summary>
public override string ToString() {
return string.Concat(this.Value, "-", this.Flag);
}
public static MyThingClass FromString(string value) {
var v = value.Split('-');
return new MyThingClass() {
Value = v[0],
Flag = Convert.ToInt32(v[1])
};
}
}

Show Name Property on a foreignkey relationship

I have a selectList of foreignkey (like a parent). Currently, the ID are binded for the value and item name. I want to change that for my Name property:
Here's my models:
public class Genus
{
public int GenusID { get; set; }
public EnumCategory Category { get; set; }
public string Name { get; set; }
public List<Species> Species { get; set; }
}
public class Species
{
public int SpeciesID { get; set; }
public int GenusID { get; set; }
public virtual Genus Genus { get; set; }
public string Name { get; set; }
}
On my Create and Edit Species page I have this code:
<select asp-for="Species.GenusID" class ="form-control" asp-items="ViewBag.GenusID"></select>
This code are generated by default when We Add Razor Page Scaffold. Well, the result are on the line 1, and what I want of result on the line 2:
<option selected="selected" value="1">1</option>
<option selected="selected" value="1">NameProperty</option> <!-- Species.Genus.Name -->
Do you have an idea to make that right ?
Thanks per advance
Looking at the code for the NavigationMetadata class in the scaffolding repo (https://github.com/aspnet/Scaffolding) I have found the following commented code which describe the behaviour.
// The default for the display property is the primary key of the navigation.
DisplayPropertyName = PrimaryKeyNames[0];
// If there is a non nullable string property in the navigation's target type, we use that instead.
var displayPropertyCandidate = navigation
.GetTargetType()
.GetProperties()
.FirstOrDefault(p => !p.IsNullable && p.ClrType == typeof(string));
if (displayPropertyCandidate != null)
{
DisplayPropertyName = displayPropertyCandidate.Name;
}
So if you want the Name property to show by default instead of the ID, then ensure it is the first string property in the model (yours already is), and then make sure it's not nullable.
protected override void OnModelCreating(ModelBuilder builder)
{
// ...
builder.Entity<Genus>().Property(l => l.Name).IsRequired();
// ...
}

how to map sitecore items using glassmapper class in web froms..?

i'm creating demo project there i create Item which contains sub-Item now i want to render these using web controller my code like this
site items created as following image
and my glass mapper code is as:
public static class GlassMapperSc
{
public static void Start()
{
//create the resolver
var resolver = DependencyResolver.CreateStandardResolver();
//install the custom services
GlassMapperScCustom.CastleConfig(resolver.Container);
//create a context
var context = Glass.Mapper.Context.Create(resolver);
context.Load(
GlassMapperScCustom.GlassLoaders()
);
GlassMapperScCustom.PostLoad();
}
public class DesktopHome
{
public virtual string Title { get; set; }
public virtual string Description { get; set; }
public virtual string LeftRotatorTitle { get; set; }
public virtual string RightRotatorTitle { get; set; }
}
public class GlobalsItem
{
public class HeaderTemplateItem
{
public class NavItem
{
public virtual string Title { get; set; }
public virtual string Link { get; set; }
public virtual IEnumerable<NavItem> Children { get; set; }
}
}
}
}
i'm able to get parent items but not able to get child items please anyone help me to figure out this issue
Define your Modal Class as:
[SitecoreClass]
public class Header
{
[SitecoreInfo(SitecoreInfoType.Url)]
public virtual string About{ get; set; }
[SitecoreField]
public virtual string Home{ get; set; }
[SitecoreField]
public virtual string Services{ get; set; }
[SitecoreField]
public virtual IEnumerable<Header> Links { get; set; }
}
Configuring the application
To configure Glass Mapper is really straight forward. Open or create a Global.ascx file in your project and on the application start add the following code:
protected void Application_Start(object sender, EventArgs e)
{
AttributeConfigurationLoader loader = new AttributeConfigurationLoader(
new string[] { "Glass.Sitecore.Mapper.Demo.Application.Domain, Glass.Sitecore.Mapper .Demo" }
);
Persistence.Context context = new Context(loader, null);
}
your view code will be as:
<div>
<h1>
<asp:Literal runat="server" ID="About" />
</h1>
<div class="body">
<asp:Literal runat="server" ID="Home" />
</div>
<div class="links">
<asp:Repeater runat="server" ID="links">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><a href='<%# DataBinder.Eval(Container.DataItem,"Url") %>'>
<%# DataBinder.Eval(Container.DataItem,"Services") %></a> </li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</div>
Next lets look at the code behind page, for simplicity everything is going in the Page_Load method:
protected void Page_Load(object sender, EventArgs e)
{
ISitecoreContext context = new SitecoreContext();
DemoClass item = context.GetCurrentItem<DemoClass>();
title.Text = item.Title;
body.Text = item.Body;
links.DataSource = item.Links;
links.DataBind();
}