ASP.NET MVC Populate DropDown thru ViewBag - c#

I am a beginner to ASP.NET MVC technology.
In my View page, I have a WebGrid that is bind to data that is passed from Controller. I also want to populate a dropdown list with the list of Tables in the database. I retrieve the tables List from a helper method. I am trying to send the List to the ViewBag and want to populate the dropdown; but can't get it. Some syntax error is only coming or the List is not accessible.
My Controller class :
[Authorize]
public ActionResult Index(int page = 1, string sort = "FirstName", string sortdir = "asc", string search = "")
{
int pageSize = 10;
int totalRecord = 0;
if (page < 1)
page = 1;
int skip = (page * pageSize) - pageSize;
var data = GetUsers(search, sort, sortdir, skip, pageSize, out totalRecord);
// Get Tables List
ViewBag.TableList = DataFiller.GetTableNames();
ViewBag.TotalRows = totalRecord;
return View(data);
}
View file :
#model List<DataStudio.Models.User>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_MemberLayout.cshtml";
<!-- data is used for grid -->
var grid = new WebGrid(canPage: true, rowsPerPage: 10);
grid.Bind(source: Model, rowCount: ViewBag.TotalRows, autoSortAndPage: false);
}
<!-- ERROR LINE -->
#Html.DropDownList("tableName", #ViewBag.TableList, "Select Table")
ERROR
Error CS1973 'HtmlHelper<List<User>>' has no applicable method named 'DropDownList' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax. 1_Views_Member_Index.cshtml Index.cshtml 82 Active
The User model doesn't contain any List nor any DropDownList. The drop down is a totally separate combo box, that I want to fill with a List items; it just contains the list of table names from the database.
I am not able to get how do I bind or populate the drop down list with the SelectLiteItem items. I googled a lot, but could not get any example with this scenario. I don't wish to add my List with my model. And, I want to populate the Tables list drop down only once.
Can anyone please help me and guide me how do I achieve the goal. Any help is highly appreciated.
Thanks
Tom
UPDATE:
The DataFilter.GetTableNames() method
public static List<SelectListItem> GetTableNames()
{
List<SelectListItem> tablesList = new List<SelectListItem>();
string sql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'";
string conStr = System.Configuration.ConfigurationManager.ConnectionStrings["DMSDbConnectionString"].ToString();
using (SqlConnection con = new SqlConnection(conStr))
{
using (SqlCommand com = new SqlCommand(sql, con)) {
con.Open();
using(SqlDataReader sdr = com.ExecuteReader() )
{
while (sdr.Read())
{
tablesList.Add(new SelectListItem
{
Text = sdr["TABLE_NAME"].ToString(),
Value = sdr["TABLE_NAME"].ToString()
});
}
}
/*
SqlDataAdapter da = new SqlDataAdapter(com);
DataSet ds = new DataSet();
da.Fill(ds);
DataTable dt = ds.Tables[0];
tablesList = (from DataRow dr in dt.Rows
select new TablesInfo()
{
TableCatalog = dr["TABLE_CATALOG"].ToString(),
TableName = dr["TABLE_NAME"].ToString(),
TableSchema = dr["TABLE_SCHEMA"].ToString(),
TableType = dr["TABLE_TYPE"].ToString(),
}).ToList();
*/
con.Close();
}
}
return tablesList;
}
I had created a class also TablesInfo to populate data in it and use strong typed object. But, as couldn't find a way to populate it, so used SelectListItem.
And as it contains only list of tables, so I don't wish it to be populated on every refresh of the page.

You can't use ViewBag dynamic object which contains List<User> directly to a DropDownList HTML helper, you need to cast it into SelectList instead:
#Html.DropDownList("tableName", (SelectList)ViewBag.TableList, "Select Table")
Additionally, DataFiller.GetTableNames() method call should returns SelectList instance:
class DataFiller
{
public SelectList GetTableNames()
{
// set select list items here
}
}
NB: I strongly prefer using a strongly typed view model instead using ViewBag or ViewData to pass a list to HTML helper like this:
#Html.DropDownListFor(model => model.tableName, Model.TableList as SelectList, "Select Table")
Related issue:
MVC3 DropDownList + ViewBag issue

As Tetsuya stated, you should be using a strongly typed view model.
You can structure your model like this:
public class MyUserCollection
{
public List<MyUser> Users { get; set; }
public SelectList TableList { get; set; }
public int TotalRows { get; set; }
public MyUserCollection(string search, string sort, string sortdir, int skip, int pageSize)
{
TableList = DataFiller.GetTableNames();
Users = GetUsers(search, sort, sortdir, skip, pageSize, out totalRecord);
}
}
Then to create your drop down:
#Html.DropDownListFor(model => model.tableName, Model.TableList as SelectList, "Select Table")
Other wise you need to cast your object:
#Html.DropDownList("tableName", (SelectList)ViewBag.TableList, "Select Table")

Please use below code i hope that will help your query.
ViewBag.TableList = DataFiller.GetTableNames();
#Html.DropDownList("ID", new SelectList(ViewBag.TableList, "ID", "Name"));

You can actually do it like below too:
#Html.DropDownListFor(m => m.tableName, (IEnumerable<SelectListItem>)ViewBag.TableList ,"select table")

Related

Automatically Filter DataTable

I have a console application connected to a SQL Server database with several tables and views. To get the entire table I so something like:
myAppDataset dsTemp = new myAppDataset();
myAppDataset.AppLogDataTable dtLog = dsTemp.AppLog;
myAppDataset.AppUserDataTable dtUser = dsTemp.AppUser;
Then when I need to filter I create a DataView:
DataView dvLog = dtLog.DefaultView;
dvLog.RowFilter = "DeptID = 1";
DataView dvUser = dtUser.DefaultView;
dvUser.RowFilter = "DeptID = 1";
That all works fine.
What I'd like to know is if there is a way modify the DataSet (or something else) so that I don't need to create the DataViews? In other words, I want every AppLogDataTable, AppUserDataTable, etc that gets created to be filtered for DeptID = 1. Essentially what I want to achieve is to be able to pass a parameter to my data class constructor that will automatically filter all of the data tables so that when they are used I don't have to worry about creating a DataView and filtering the table every time (which also necessitates the passing of the original filtering parameters).
I tried creating a DataView and overwriting the original object, but got an error that the DataTable couldn't be casted or something to that effect:
myAppDataset dsTemp = new myAppDataset();
myAppDataset.AppLogDataTable dtLog = dsTemp.AppLog;
DataView dvLog = dtLog.DefaultView;
dvLog.RowFilter = "DeptID = 1";
dtLog = (myAppDataset.AppLogDataTable)dvLog.ToTable();
Any help is greatly appreciated.
some possible suggestions:
use Linq2Object, and not DataView at all
var filterStep1 = dtUser.Where(x => x.DeptID == 1);
var filterStep2 = filterStep1.Where(x => x.XYZ < 40);
Console.WriteLine(filterStep2);
is equivalent to:
var filter = dtUser.Where(x => x.DeptID == 1 && x => x.XYZ < 40);
Console.WriteLine(filter);
edit the sql query
you can filter in the sql query.
in TypedDataSet case, double-click on myAppDataset in the solution-explorer, click on the Fill, GetData() that appears under the table-box.
in property window (F4), click double-click on Select Command property. the query-designer shown. add the filter to query (if you not want write the 1 but parameter, type ? in the criteria - it create parameter for command automaticaly).
use List for criteria
another solution is create a list of criteria, and join them to RowFilter:
var criteria = new List<string>();
criteria.Add("DeptID = 1");
criteria.Add("XYZ < 40");
dvUser.RowFilter = string.Join(" AND ", criteria);
You really shouldn't be reading data from the database if you don't intend to use it. Filter your SQL query.
select somecolumns from sometable where DeptID = 1
However, let's pretend for a moment that you're reading all the data into memory for caching purposes or something like this. Don't put that into a DataSet, DataTable, or DataView. Those are outdated constructs. They're slow, inefficient, and give you none of the benefits of binding to a strongly typed object.
Instead, create a type to represent your data. Since you don't give much context, I'm going to pretend you're dealing with Students that have a many to one relationship with Departments.
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int DepartmentId { get; set; }
}
Now you have some choices. You can use ADO.NET to get the data.
public class StudentSqlServerRepository
{
private readonly string _connectionString;
public StudentSqlServerRepository(string connectionString)
{
_connectionString = connectionString;
}
public List<Student> GetStudentsByDepartmentId(int departmentId)
{
var students = new List<Student>();
using(var connection = new SqlConnection(_connectionString))
using(var command = new SqlCommand("select Id, Name, DepartmentId from students where DepartmentId = #DepartmentId", connection))
{
command.Parameters.Add(new SqlParameter("DepartmentId", SqlDbType.Int).Value = departmentId);
connection.Open();
using(var reader = command.ExecuteReader())
{
while(reader.Read())
{
var student = new Student();
student.Id = (int)reader["Id"];
student.Name = (string)reader["Name"];
student.DepartmentId = (int)reader["DepartmentId"];
students.Add(student);
}
}
}
return students;
}
}
But that's a lot of yucky code. Fortunately, Dapper, a micro ORM, can make this a lot cleaner.
public class StudentSqlServerRepository
{
private readonly string _connectionString;
public StudentSqlServerRepository(string connectionString)
{
_connectionString = connectionString;
}
public List<Student> GetStudentsByDepartmentId(int departmentId)
{
using(var connection = new SqlConnection(_connectionString))
{
var students = connection.Query<Student>("select Id, Name, DepartmentId from students where DepartmentId = #DepartmentId", new { DepartmentId = departmentId}).AsList();
return students;
}
}
}
Now getting your students is as easy as
var studentRepository = new StudentSqlServerRepository(ConfigurationManager.ConnectionStrings["StudentDatabase"].ConnectionString);
var students = studentRepository.GetStudentsByDepartmentId(1);
//let's pretend this is Web Forms and we want to bind to a control
StudentsGridView.DataSource = students;
StudentsGridView.DataBind();
//let's pretend it's MVC and we want to return a View
return View(students);
Compare the memory usage, amount of network traffic, query execution time, and overall ease of this approach as opposed to using a DataTable and filtering in memory.

ASP.net MVC 5 Razor dropdown box

Hey all I am new to Razor MVC and wanted to make a select box that has the past 10 years listed inside it (2016, 2015, 2014, etc....).
This is my current Controllers code:
public ActionResult loadPast10Years()
{
List<int> last10Years = new List<int>();
int currentYear = DateTime.Now.Year;
for (int i = currentYear - 10; i < currentYear; i++)
{
last10Years.Add(i);
}
ViewBag["last10Years"] = last10Years;
return View();
}
And my Razor code:
#Html.DropDownList("last10Years", (SelectList)ViewBag["last10Years"], "--Select One--")
But I have an error when loading the page that says:
InvalidOperationException: There is no ViewData item of type 'IEnumerable' that has the key 'last10Years'.
So... What am I missing?
This is how I would do it in the view
#Html.DropDownList("Last Ten Years", (IEnumerable<SelectListItem>)ViewBag.LastTenYears, "Select A Year")
and in your Action
List<int> last10Years = new List<int>();
int currentYear = DateTime.Now.Year;
for (int i = currentYear - 10; i < currentYear; i++)
{
last10Years.Add(i);
}
ViewBag.LastTenYears = new SelectList(last10Years);
You can see a demo here
Following from your comment please find below my updated answer.
I would first create a Model class which we will be using in our view. In this model class you can have your appropriate properties. For now we're only going to be using SelectlistItem
so our class will look like
public class ViewModel
{
public IEnumerable<SelectListItem> LastTenYears { get; set; }
}
Then in our controller we can create a method which will provide us the information for our drop down.
public IEnumerable<SelectListItem> GetLastTenYears()
{
List<SelectListItem> ddl = new List<SelectListItem>();
int currentYear = DateTime.Now.Year;
for (int i = currentYear - 10; i < currentYear; i++)
{
ddl.Add(new SelectListItem { Text = i.ToString(), Value = i.ToString() });
}
IEnumerable<SelectListItem> lastTenYears = ddl;
return lastTenYears;
}
Now we want to pass this data to the view. For argument sake I will use Index as a view but you can pass it to whatever view you like. So we will change our Index action to
public ActionResult Index()
{
ViewModel viewModel = new ViewModel();
viewModel.LastTenYears = GetLastTenYears(); //get the drop down list
return View(viewModel); //we're passing our Model to the view
}
Finally, we want to make sure our view knows which Model to use so we will do the following the beging of the Index.cshtml file
#model YourNameSpace.ViewModel
and our DropDownList helper method will now change to point to the property in our Model class as
#Html.DropDownList("Last Ten Years", Model.LastTenYears, "Please select a year")
There are few issue in your code right now.
Don't name the ViewBag key same as the DropDownList name, they don't
work well together, you can change the ViewBag Key name to something like last10YearsOptionsinstead oflast10Years`, so that it is different than control name.
You have not create SelectList in controller before adding to ViewBag, but you are casting it to SelectList in View.
In ViewBag values are stored like ViewBag.SomeKey= "SomeValue", but you are doing it wrong way.
After Fixing the above problems your code will look like :
ViewBag.last10YearsOptions = last10Years.Select(x => new SelectListItem()
{
Text = x.ToString(),
Value = x.ToString()
}
);
and then in View:
#Html.DropDownList("last10Years",
"--Select One--",
ViewBag.last10YearsOptions as IEnumerable<SelectListItem>,
null )
ViewBag is not a dictionary with key value pairs.
also DropDownList works with ICollection ithink
so this code works form
#Html.DropDownList("last10Years", new SelectList(ViewBag.last10YearsOptions), "Select one from here")
Controller is here;
public ActionResult loadPast10Years()
{
List<int> last10Years = new List<int>();
int currentYear = DateTime.Now.Year;
for (int i = currentYear - 10; i < currentYear; i++)
{
last10Years.Add(i);
}
ViewBag.last10Years = new SelectList(last10Years);
return View();
}
And View
#Html.DropDownList("last10Years", "--Select One--")

MVC5 populating DropDownList [duplicate]

This question already has answers here:
using DropdownlistFor helper for a list of names
(2 answers)
Closed 7 years ago.
I have just started developing using the MVC 5 design pattern, I'm trying to populate my DropDownList with data from the database, this is what I have in my Country model:
public class Country
{
public DataTable GetAllCountries()
{
string theSql = "SELECT * FROM Country";
IDataAccess dataAccess = new DataAccess();
return dataAccess.GetData(theSql);
}
}
Then within my controller I have:
public ActionResult Index()
{
List<SelectListItem> objResult = new List<SelectListItem>();
Models.Country country = new Models.Country();
DataTable result = country.GetAllCountries();
foreach(DataRow item in result.Rows)
{
SelectListItem temp = new SelectListItem();
temp.Value = item["id"].ToString();
temp.Text = item["country"].ToString();
objResult.Add(temp);
}
ViewBag.DropDownResult = objResult;
return View();
}
Then in my Partial view I have:
#model MyProject.Models.Country
#Html.DropDownListFor(ViewBag.DropDownResult as List<SelectListItem>)
Howvever on DropDownListFor I receieve this error:
No overload for method 'DropDownListFor' takes 1 arguments
Does anyone know what I am doing wrong? If I'm correctly following the MVC pattern also?
Thanks guys
You need to specify in which object is the property you want to display.
#Html.DropDownListFor requires atleast 2 parameters. The first should be the object and the second the list which containts the items.
Something like:
#model MyProject.Models.Country
#Html.DropDownListFor(m => m.SomeProperty, ViewBag.DropDownResult as List<SelectListItem>)

Invalid Operation Exception passing to View

I am trying, to no avail to display a dropdown list of all units a user doesnt already have. So i have List A with all Units and List B with all Units the user has. What i want is List C which is basically List A with List B removed from it. I have so far managed to filter out the data but i cant seem to display it in my View. All i get is a blank dropdown list. Can anyone see where im going wrong??
public ActionResult AddUnit(String usrCode)
{
var units = unitsClient.GetAllunits();
var allunitsCode = (from s in units select s.unitCode).ToList();
var thisUnitCode = (from s in db.Units
where s.UsrCode == usrCode
select s.UnitCode).ToList();
var notGot = allunitsCode.Except(thisUnitCode);
List<unitsummaryDTO> list = UnitList(units, notGot);
ViewBag.unitCode = new SelectList(list, "unitCode", "unitTitle");
var model = new UserUnit { UsrCode = usrCode };
return View("AddUnit", model);
}
private List<unitsummaryDTO> UnitList(unitsService.unitsDTO[] units, IEnumerable<string> notGot)
{
var allunits = unitsClient.GetAllunits();
var allunitsCode = (from s in allunits select s.unitCode).ToList();
IEnumerable<String> list1 = allunitsCode;
IEnumerable<String> list2 = notGot;
var listFinal = list1.Union(list2).toList;
return listFinal.Select(x => new unitsummaryDTO(){unitCode = x}).ToList();
}
This is my View model. But all i get is a blank drop down?? Can anyone help me out.
#model Projv1.UserUnit
#Html.HiddenFor(model => model.unitCode)
#Html.DropDownList("UnitCode")
It would be blank because #Html.DropDownList("UnitCode") doesn't have a source. If you look at MSDN for Html.DropDownList, the one your most likely trying to use is DropDownList(String, IEnumerable<SelectListItem>).
Your putting your select list into the ViewBag as unitCode so try:
#Html.DropDownList("Unit Code", ViewBag.unitCode);
A much easier way of handling this is to extend UserUnit as a ViewModel (or create something) to have the items needed by the SelectList on it and let MVC do the heavy lifting in the binding.
public class UserUnit
{
// ... other properties
IEnumerable<unitsummaryDTO> UnitCodes { get; set; }
public string MyUnitCode { get; set; }
}
Then
#Html.DropDownListFor(n => n.MyUnitCode,
new SelectList(Model.UnitCodes, "unitCode", "unitTitle"))

Load a list from a SQL Server database to C# combobox

I have a database with 2 categories that I turn into a list and plan to use it as a data source for a drop down combobox in C#
Category B is connected to category B for example (in database):
CatA CatB
a 1
a 2
b 3
b 4
The plan is to use droplist to choose catA and on change it will load CatB to the 2nd droplist.
So if I choose CATA=a I will get CATB=1,2
The code to get CATA
public List<string> getCatAlist()
{
List<string> catAlist = new List<string>();
List<string> filteredList = new List<string>();
_con.Open();
_cmd.CommandText = "SELECT * FROM category";
var dr = _cmd.ExecuteReader();
while (dr.Read())
catAlist.Add(dr["catA"].ToString());
_con.Close();
filteredList = catAlist.Distinct().ToList();
return filteredList;
}
The code to get CATB
public List<string> getCatBlist(string catA)
{
List<string> catBlist = new List<string>();
_con.Open();
_cmd.CommandText = "SELECT * FROM category WHERE catA='"+catA+"';";
var dr = _cmd.ExecuteReader();
while (dr.Read())
catBlist.Add(dr["catB"].ToString());
_con.Close();
return catBlist;
}
The problem is to set the list's as datasource for the combobox
I open a connection to the database and on the first run it loads the list, but when I try to use it again it converts it to a static list for the datasource.
Any idea on how to fix this?
If your categories are not very dynamic you can create Stored Proc where you make 2 calls - this optional, you can make two separate calls to DB
Select ... From Cat...
Select ... From Cat...
In .Net use
cmd.ExecuteReader
And use
reader.NextResult
...to retrieve each set of records.
Create classes for your categories (pseudo-code)
class CatA {
int value
string display
}
class CatB {
int parent
int value
string display
}
Fill your lists
List<CatA> listA;
List<CatA> listB;
Set your CatA combo properties
cboA.valuemember = "value";
cboA.displaymember = "display";
cboA.datasource = listA; // set DS last for better performance
Now, you can do this on listA SelectedIndexChanged
// Read comment
var subListCatB = listB.Where(i => i.parent == ((CatA)listA.SelectedItem).value).ToList()
//I think you need to use 'where' here but if you have A, which has no B then you need null check
cboB.valuemember = "value";
cboB.displaymember = "display";
cboB.datasource = subListCatB ; // set DS last for better performance
This is it

Categories

Resources