Get specific dataTable cell values in View (ASP.NET MVC) - c#

I am trying to find a way to access specific cells in a DataTable in View. The DataTable was created in controller.
Code in conroller:
[ChildActionOnly]
public ActionResult _ls()
{
var getXMLlivescore = new HtmlDocument();
getXMLlivescore.Load("D://lscopy.xml");
DataTable matchTable = new DataTable();
matchTable.Columns.Add("put2forEventOr1", typeof(int));
matchTable.Columns.Add("country", typeof(string));
...
matchTable.Columns.Add("min", typeof(string));
matchTable.Columns.Add("extramin", typeof(string));
foreach (HtmlNode match in category.SelectNodes(".//match")){
//code to get xml tags
matchTable.Rows.Add(put2forEventOr1, country, ....., min, extramin);
}
return PartialView(matchTable);
}
and the partialView code:
<table>
#foreach (DataRow row in Model.Rows)
{
//get cell in row[0]
#if (row[0] == 3){
do some work
}
}
</table>
How can I iterate through DataTable cells in view and get specific cells?

I really don't understand why do you need to use a DataTable. You can always create a class with structure you need. It will be much easier to us simple POCO's in your views.
You haven't provided your XML so I made some examples for very simple version:
<Elements>
<Element>
<Country>Peru</Country>
<Min>20</Min>
</Element>
<Element>
<Country>Armenia</Country>
<Min>9</Min>
</Element>
</Elements>
For such XML you can create a class that will represent an Element:
public class Element
{
public string Country { get; set; }
public int Min { get; set; }
public string NotXmlProperty { get; set; }
}
And then you can use your method of reading XML or for example this one:
var xDoc = XDocument.Load(xmlFilePath);
IEnumerable<Element> elements = xDoc
.Descendants("Element")
.Select(x => new Element
{
Country = x.Element("Country").Value,
Min = Convert.ToInt32(x.Element("Min").Value),
NotXmlProperty = "Value"
});
After that accessing your data in the view should be very simple:
#model IEnumerable<Element>
<table>
#foreach(var element in Model)
{
<tr>
<td>#element.Country</td>
<td>#element.Min</td>
<td>#element.NotXmlProperty</td>
</tr>
}
<table>

Related

C# Easy drag and drop way to create DataTables from SQL?

When dealing with really small apps and the sqlbulkcopy, I normally create datatables by either using a FILL on an empty datatable OR I just type out something like this
DataTable dtGrps = new DataTable();
dtGrps.Columns.Add("objectGuid", typeof(Guid));
dtGrps.Columns.Add("DN", typeof(string));
dtGrps.Columns.Add("CN", typeof(string));
dtGrps.Columns.Add("groupType", typeof(string));
dtGrps.Columns.Add("description", typeof(string));
dtGrps.Columns.Add("whenCreated", typeof(string));
dtGrps.Columns.Add("whenChanged", typeof(string));
but it occurred to me that surly there is a built in way (non EF or Linq) to create all the code above by some drag in drop method. I mean I am using VS2017, surely MS has added this feature and I have just missed it is all.
So does this exist?
This is a very rough implementation, just intended as a starting point because my goal here isn't to write a new library. It could use a lot of optimization. But you can use strongly typed objects, use reflection to generate a DataTable based on the objects, and then use SqlBulkCopy to insert that.
using System;
using System.Collections.Generic;
using System.Data;
namespace StronglyStypedSqlBulkCopy
{
class Program
{
static void Main(string[] args)
{
List<Car> cars = GetSampleData();
DataTable dataTable = ConvertToDataTable(cars);
Console.WriteLine("Press any key to exit.");
Console.ReadKey(true);
}
public static List<Car> GetSampleData()
{
return new List<Car> {
new Car { Id = 1, Make = "Toyota", Model = "Tacoma", DateOfManufacture = DateTime.Now.AddDays(-1) },
new Car { Id = 2, Make = "Ford", Model = "Raptor", DateOfManufacture = DateTime.Now.AddDays(-2) },
new Car { Id = 3, Make = "Ram", Model = "1500", DateOfManufacture = DateTime.Now.AddDays(-3) }
};
}
public static DataTable ConvertToDataTable<T>(IEnumerable<T> objects)
{
var properties = objects.GetType().GetGenericArguments()[0].GetProperties();
var table = new DataTable();
foreach (var property in properties)
{
var columnName = property.Name; //may want to get from attribute also
//probably want to define an explicit mapping of .NET types to SQL types, and allow an attribute to specifically specify the SQL type
table.Columns.Add(columnName, property.PropertyType);
}
//probably want to cache the mapping from above in a real implementation
foreach (var obj in objects)
{
var row = table.NewRow();
foreach (var property in properties)
{
var columnName = property.Name; //may want to get from attribute also
var propertyValue = property.GetValue(obj);
row[columnName] = propertyValue;
}
table.Rows.Add(row);
}
return table;
}
}
public class Car
{
public int Id { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public DateTime DateOfManufacture { get; set; }
}
}
Once you have a nice implementation of ConvertToDataTable, it's simply a matter of defining strongly typed classes, which are much easier to work with than raw DataTables.

Add checkbox fields to datatable based table MVC 4 Razor

I am using MVC 4 Visual Studio 2012 with Razor.
I am generating a table based off of several tables pulled into a dataset from a remote call to a SQL server.
I want to be able to output these tables onto the webpage and then create two columns of checkboxes beside them in order to assign them to one area or another (it essentially sorts data into accepted and not accepted, while allowing some to continue pending if a decision has not been made).
I currently have all the tables in the dataset being assigned to datatables in the controller and then exported to the razor page. I do not have a model set up for this as of yet and I'm not sure what I would require in one if I did.
This is my current View:
#{
ViewBag.Title = "Requisitions";
}
<table class="table">
<thead>
<tr>
#foreach (System.Data.DataColumn col in Model.Columns)
{
<th class ="td">#col.Caption</th>
}
</tr>
</thead>
<tbody>
#foreach(System.Data.DataRow row in Model.Rows)
{
<tr>
#foreach (var cell in row.ItemArray)
{
<td class="td">#cell.ToString()</td>
}
</tr>
}
</tbody>
</table>
This is my current controller:
DataTable R = new DataTable();
public void GetData()
{
string connString = "Data Source=.;database=dataBase;Integrated Security=SSPI";
DataSet dataset = new DataSet();
SqlDataAdapter adapter = new SqlDataAdapter("dbo.procApprovalSelectPending", connString);
using (adapter)
{
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
adapter.Fill(dataset);
}
int count = dataset.Tables.Count;
for (int i = 0; i < dataset.Tables.Count; i++)
{
// Do something for each recordset (11 recordsets)
if (i == 0)
{
R = dataset.Tables[i];
}
}
dataset.Dispose();
adapter.Dispose();
}
public ActionResult Rs()
{
GetData();
return View(R);
}
I have more datatables than shown but they were removed to conserve space.
To sum it up, I would like two checkbox columns that are aligned with each row that is created from the datatable that allow me to choose that portion of data to send back to the server what has been changed with it, and creating a dynamic checkbox for each row was giving me an error such that :
#foreach(System.Data.DataRow row in Model.Rows)
{
<tr>
#foreach (var cell in row.ItemArray)
{
<td class="td">#cell.ToString()</td>
}
<td class="td">#Html.CheckBoxFor(m => m.Checkbox)</td>
</tr>
}
"An expression tree may not contain a dynamic operation"
Thanks in advance!
You should create a view model to represent the properties you want to display, including 2 additional boolean properties for 'accepted' and 'not accepted'. Assuming your columns are ID and Name
public class MyModel
{
public int ID { get; set; }
public string Name { get; set; }
public bool Accepted { get; set; }
public bool NotAccepted { get; set; }
}
and create a collection based on each row in your table that you want to display
public ActionResult Rs()
{
List<MyModel> items = new List<MyModel>();
// Populate items from your datatable
return View(items);
}
then in your view
#model List<MyModel>
#using (Html.BeginForm()
{
<table>
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>#Html.TextBoxFor(m => m[i].ID)</tr>
<td>#Html.TextBoxFor(m => m[i].Name)</tr>
<td>#Html.CheckBoxFor(m => m[i].Accepted)</tr>
<td>#Html.CheckBoxFor(m => m[i].NotAccepted)</tr>
</tr>
}
</table>
<input type="submit" value="Save" />
}
then in your post method
[HttpPost]
public ActionResult Rs(List<MyModel> model)
{
foreach(MyModel item in model)
{
if(item.Accepted) {.. // do something
else if (item.NotAccepted) { .. // do something else
else {.. // do another thing
}
}
Use Following pattern
I have Created one static Class that is called as CommonUtilities it is giving me FormCollection,Checkboxname and valueofKey
public static class CommonUtilities
{
public static List<string> GetCheckboxSelectedValue(FormCollection frm, string checkboxname, string value)
{
List<string> retls = new List<string>();
var fileIds = frm[value].Split(',');
var selectedIndices = frm[checkboxname].Replace("true,false", "true").Split(',').Select((item, index) =>
new {
item= item,
index= index
}).Where(row=>row.item =="true")
.Select(row => row.index).ToArray();
if (selectedIndices.Count() > 0)
{
retls.AddRange(selectedIndices.Select(index => fileIds[index]));
}
return retls;
}
}
the above Function will be applied as below
Controller
List<string> selectedKeypair = CommonUtilities.GetCheckboxSelectedValue(frm, "m.BoolSelectedVal", "m.Key");
view
#foreach (MVCCareerModule.Models.Requirement m in Model.RequirementSearchResult)
{
<tr>
<td>
#Html.CheckBoxFor(modelitem => m.Apply)
#Html.HiddenFor(modelitem => m.Req_ID, new { Value = m.Req_ID })
</td>
</tr>
}
You will receive all Selected IDs in selectedKeypair

Generic way of creating XML files in C#

I am trying to create a class which saves/reads multiple XML files using LINQ and Genertics.
I am looking for generic way of saving XMl files of multiple type (i.e data in them)
Every XML file will have following format
<ROOT>
<!-- First Element/First Row -->
<NODE>
<COL1>Some value</COL1>
.....
<COLn>Some value</COLn>
</NODE>
.........
<!-- Nth Element = nth row -->
<NODE>
<COL1>Some value</COL1>
.....
<COLn>Some value</COLn>
</NODE>
</ROOT>
Every file will have a different ROOT, NODE and COLx. The Number of columns and data in them depends on the Multi-Dim array input. This input array also gives the number of NODES tags in xml (elements in array).
A method to save an XML file looks like
public void SaveFirstXmlFile()
{
XElement xdoc = new XElement("ThisDocsRoot");
//Iterate for number of rows(elements of data)
for (int nodes= 1; nodes<= NUMBER_OF_NODES; nodes++)
{
xdoc.Add(new XElement(row,
new XElement("Col 1", "Some Value"),
new XElement("Col 2", "Some Value"),
new XElement("Col 3", "Some Value")
));
}
xdoc.Save("/Path/To/XML/File");
}
I wanted to tweak this method so that it works for multiple XML files.I don't know if it is correct way of doiung it, but I strated creating CLasses which define the root,node,columns and path for the XML file. and The data comes from Multi-Dim Arrays created by some other classes.
private class AClassforSomeXMLFile
{
private readonly String _root;
private readonly String _row;
private readonly String[] _columns;
private readonly String _exportPath;
public UsageData()
{
_exportPath = string.Format(#"{0}\xyz.xml",Path.GetDirectoryName(Application.ExecutablePath));
_root = "ROOT";
_row = "NODE";
_columns = new string[]
{
"COL1","COL2", "COL3","COL4",
};
}
public string ROOT { get { return _root; } }
public string ROW { get { return _row; } }
public string[] COLS { get { return _columns; }}
public string EPATH { get { return _exportPath; }}
}
You can add constructor to AClassforSomeXMLFile class, to populate root, row and columns values, and then pass instance of definition to your SaveFirstXmlFile function:
private class XmlDefinition
{
public string ROOT { get;set; }
public string ROW { get;set; }
public string[] COLS { get;set; }
public string EPATH { get;set; }
}
void Foo()
{
var employeeDefinition = new XmlDefinition
{
ROOT = "Employees",
ROW = "Employee",
COLS = new[] { "Name", "Address", "Department", "Salary" },
EPATH = string.Format(#"{0}\employee.xml",Path.GetDirectoryName(Application.ExecutablePath))
};
SaveFirstXmlFile(employeeDefinition); //save employees
var productDefinition = new XmlDefinition
{
ROOT = "Products",
ROW = "Product",
COLS = new[] { "Name", "Description", "Cost" },
EPATH = string.Format(#"{0}\products.xml",Path.GetDirectoryName(Application.ExecutablePath))
};
SaveFirstXmlFile(productDefinition); //save products
}
public void SaveFirstXmlFile(AClassforSomeXMLFile definition)
{
XElement xdoc = new XElement(definition.ROOT);
//Iterate for number of rows(elements of data)
for (int nodes = 1; nodes <= NUMBER_OF_NODES; nodes++)
{
var cols = from c in definition.COLS select new XElement(c, "Some Value");
xdoc.Add(new XElement(definition.ROW, cols.ToArray()));
}
xdoc.Save(definition.EPATH);
}
I do not fully understand the ask here, but It looks like it might be satisfied if you format your XML like this
<NODE>
<COL>Some value</COL>
.....
<COL>Some value</COL>
</NODE>
and then you can read all your COLs into a list
XElement xdoc = new XElement("ThisDocsRoot");
List<XElement> Cols = xdoc.Elements("COL").ToList();

How to set List<List<double>> (Or two dimensional array) as data source to DataGrid

I have List<List<double>> with values and wpf datagrid.
How can I set this as dataSource to my dataGrid?
I have tried following:
public class DataContainer
{
public List<List<double>> List { get; set; }
public List<string> Headers { get; set; }
}
private void InitializeGrid(DataContainer container)
{
var table = new DataTable();
foreach (var header in container.Headers)
{
dataGrid1.Columns.Add(new DataGridTextColumn(){Header = header});
table.Columns.Add(header);
}
foreach (var lst in container.List)
{
var dr = table.NewRow();
var array = (from o in lst
select (object)o).ToArray();
dr.ItemArray = array;
table.Rows.Add(dr);
}
foreach (var row in table.Rows)
{
dataGrid1.Items.Add(row);
}
// dataGrid1.ItemsSource = table.Rows;
}
And this only add headers and empty rows.
You can go two directions but you need to pick one.
One:
Create the DataTable (not the columns). Use the headers to name the columns in the DataTable. Bind the DataTable with autogenerate columns.
Two:
Do NOT create the DataTable. Bind to List (using List as a property name is a bad practice and confusing). Then you you bind the column content to something like List[0], List[1]. I am not sure what the syntax is as I have done List where MyClass has a public List MyRows and then the syntax for the content binding is MyRows[0], MyRows[1] ....

asp.net databound menu multilevel

I am currently using an asp.net menu control to load from a table parent/child items. The problem I am having is that if the child has another child. My code is kindof static in that sense and I can't seem to find a better or "the" way to do it. I have seen sitemap as datasources but i don't need a sitemap and feel that would just be overkill for what I need to achieve.
foreach (ClassName option in list)
{
MenuItem module = new MenuItem(option.Description.ToLower(), "", "", option.Url + "?option=" + option.Optionid);
module.Selectable = true;
navigation.Items.Add(module);
//this is my second level
foreach (ClassName child in listfromparent(option.Optionid))
{
MenuItem childmenu = new MenuItem(child.Description.ToLower(), "", "", child.Url + "?option=" + child.Optionid);
module.ChildItems.Add(childmenu);
}
}
as you can see this works but for 2 levels :(
and of course i could put another childlevel inside child to create the 3rd level but what if there is a 4th, 5th? So that's why I need it to do it itself. I noticed treeview has onpopulate but apparently Menu doesn't. Thanks in advance.
Here's one way you could do it.
Represent parent/child relationship in your table with an adjacency list
Map that adjacency list into a tree structure
Convert that tree structure into your structure of menu items
Maybe you could skip that middle step and map the adjacency list straight to a tree of MenuItems, maybe with some extension methods on MenuItem.
But anyway...
Default.aspx
<%# Page Language="C#" Inherits="MenuTreeDemo.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head runat="server">
<title>Default</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Menu ID="MyMenu" runat="server" StaticDisplayLevels="3" />
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Collections.Generic;
namespace MenuTreeDemo
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
MenuNode root = ConvertTableToTree(GetTreeTable());
foreach (MenuNode topLevelNode in root.Children)
{
MyMenu.Items.Add(topLevelNode.ToMenuItem()); // Visits all nodes in the tree.
}
}
}
// The menu tree as an adjacency list in a table.
static DataTable GetTreeTable()
{
DataTable table = new DataTable();
table.Columns.Add("Id", typeof(int));
table.Columns.Add("Description", typeof(string));
table.Columns.Add("Url", typeof(string));
table.Columns.Add("ParentId", typeof(int));
table.Rows.Add(1, "TopMenu1", "/foo.html", 0);
table.Rows.Add(2, "SubMenu1.1", "/baz.html", 1);
table.Rows.Add(3, "SubMenu1.2", "/barry.html", 1);
table.Rows.Add(4, "SubMenu1.2.1", "/skeet.html", 3);
table.Rows.Add(5, "TopMenu2", "/bar.html", 0);
table.Rows.Add(6, "TopMenu3", "/bar.html", 0);
table.Rows.Add(7, "SubMenu3.1", "/ack.html", 6);
return table;
}
// See e.g. http://stackoverflow.com/questions/2654627/most-efficient-way-of-creating-tree-from-adjacency-list
// Assuming table is ordered.
static MenuNode ConvertTableToTree(DataTable table)
{
var map = new Dictionary<int, MenuNode>();
map[0] = new MenuNode() { Id = 0 }; // root node
foreach (DataRow row in table.Rows)
{
int nodeId = int.Parse(row["Id"].ToString());
int parentId = int.Parse(row["ParentId"].ToString());
MenuNode newNode = MenuNodeFromDataRow(row);
map[parentId].Children.Add(newNode);
map[nodeId] = newNode;
}
return map[0]; // root node
}
static MenuNode MenuNodeFromDataRow(DataRow row)
{
int nodeId = int.Parse(row["Id"].ToString());
int parentId = int.Parse(row["ParentId"].ToString());
string description = row["Description"].ToString();
string url = row["Url"].ToString();
return new MenuNode() { Id=nodeId, ParentId=parentId, Description=description, Url=url };
}
}
}
MenuNode.cs
using System;
using System.Collections.Generic;
using System.Web.UI.WebControls;
namespace MenuTreeDemo
{
public class MenuNode
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Description { get; set; }
public string Url { get; set; }
public List<MenuNode> Children { get; set; }
public MenuNode ()
{
Children = new List<MenuNode>();
}
// Will visit all descendants and turn them into menu items.
public MenuItem ToMenuItem()
{
MenuItem item = new MenuItem(Description) { NavigateUrl=Url };
foreach (MenuNode child in Children)
{
item.ChildItems.Add(child.ToMenuItem());
}
return item;
}
}
}

Categories