I have a menu control in my Master page.T he name of the menu and corresponding url is coming from the database. If a menu has a sub menu it is also showing properly.
But the problem arises if a sub menu has a child menu.
My database table has 4 columns
MenuId || MenuName || ParentId || URL.
and the code is
private void getMenu()
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
ds = objSec.ShowMenu(s_UserId);
dt = ds.Tables[0];
DataRow[] drowpar = dt.Select("ParentID=" + 0);
foreach (DataRow dr in drowpar)
{
menuBar.Items.Add(new MenuItem(dr["MenuName"].ToString(), dr["MenuID"].ToString(),
"", dr["URL"].ToString()));
}
foreach (DataRow dr in dt.Select("ParentID >" + 0))
{
try
{
MenuItem mnu = new MenuItem(dr["MenuName"].ToString(), dr["MenuID"].ToString(),
"", dr["URL"].ToString());
menuBar.FindItem(dr["ParentID"].ToString()).ChildItems.Add(mnu);
}
catch (Exception ex)
{
}
}
}
The approach in your sample might lead to incorrect results if sub-items are contained in the table before their parent-item. In addition, the empty catch-block might hide any errors. Therefore, I'd recommend another approach.
Instead of looping the table, you can also use recursion to fill the control. This removes the amount of duplicated code:
private void getMenu()
{
DataSet ds = objSec.ShowMenu(s_UserId);
DataTable dt = ds.Tables[0];
AddMenuItems(dt, 0, menu.Items);
}
private void AddMenuItems(DataTable dt, int parentId, MenuItemCollection items)
{
DataRow[] rows = dt.Select("ParentID=" + parentId.ToString());
foreach(var dr in rows)
{
var id = (int) dr["MenuID"];
var menuItem = new MenuItem(dr["MenuName"].ToString(), id.ToString(),
"", dr["URL"].ToString());
items.Add(menuItem);
// Add subitems
AddMenuItems(dt, id, menuItem.ChildItems);
}
}
The sample first calls the AddMenuItems method for the top-level items (ParentID = 0). After each item is added, its children are added by calling the AddMenuItems method again (hence the term "recursive"), providing the id of the top-level item as parent. For each 2nd level child, the method is called again and so on.
Related
I would like to ask how to copy and save selected elements from one dataGridView to another? In one dataGridView, I have elements, that can be selected, and upon selection, they are then transferred to the other dataGridView, where they will be ready for printing on paper. However, with the code below, it doesn't copy the elements correctly, as it displays ContextMenuStrip, DefaultCellStyle, DividerHeight, etc...
It also doesn't save my selection, but instead overwrites it everytime I choose new rows. How exactly do you copy and save elements (rows) from one dataGridView to another? I would like to avoid doing it with clicking, as there will be multiples of elements that need to be ready for printing.
private void button5_Click(object sender, EventArgs e)
{
dataGridView2.DataSource = dataGridView1.SelectedRows;
}
This is my example, try to following this perhap?
if (GMDSP1.Rows.Count > 0)
{
DataTable _dt1 = new DataTable();
DataTable _dt2 = new DataTable();
DataGridViewRow gvdr = GMDSP1.CurrentRow;
DataRow[] drArr = _dt1.Select("Name= '" + gvdr.Cells["Name1"].Value.ToString() + "'");
if (drArr.Length > 0)
{
DataRow dr = _dt2.NewRow();
if (_dt2.Columns.Count == 0)
{
foreach (DataColumn dc in _dt1.Columns)
{
DataColumn newDC = new DataColumn(dc.ColumnName, dc.DataType);
_dt2.Columns.Add(newDC);
}
}
dr["ID"] = drArr[0]["ID"].ToString();
dr["Name"] = drArr[0]["Name"].ToString();
_dt2.Rows.Add(dr);
_dt1.Rows.Remove(drArr[0]);
_dt1.AcceptChanges();
_dt2.AcceptChanges();
GMDSP1.DataSource = _dt1;
GMDSP2.DataSource = _dt2;
I am searching a PDF file for a keyword and returning the pages on which that keyword was found. If the keyword IS FOUND, I'm returning a list of pages and the fileName. However, if the keyword was NOT FOUND in the PDF file, I want to deleted the row in the datatable.
public DataTable dtPubSearchResultsFromFiles(string sqlQuery, string safeKeyword)
{
// Returns a datatable of publication search results based on PDF files.
SqlConnection con = new SqlConnection(getConnectionString());
SqlCommand cmd = new SqlCommand(sqlQuery, con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
dt.Columns.Add("Pages", typeof(string));
da.Fill(dt);
dt.PrimaryKey = new DataColumn[] { dt.Columns["publicationID"] };
foreach (DataRow row in dt.Rows)
{
//call search function to look for keyword
List<int> myPages = new List<int>();
string fileName = row["linkToPublicationPDF"].ToString();
myPages = ReadPdfFile(fileName, safeKeyword);
if (myPages.Count > 0)
{
string pagelist = "";
foreach (int page in myPages)
{
pagelist = pagelist + page + " ";
}
row["Pages"] = pagelist;
}
else
{
//remove/delete the row from the datatable if "myPages.Count" is 0
dt.Rows.Remove(row);
}
}
return dt;
}
When I add this ("dt.Rows.Remove(row)"), I get this error when the page is called "System.InvalidOperationException: Collection was modified; enumeration operation might not execute."
Suggestions? Comments? Fixes? All are welcome...
Bob
Your code is getting some data from the database such that your program can work with it.
The exception you're getting is because your you're modifying (by removing an element) the collection you're iterating on and that's not possible.
You can solve this by creating a temporary List where you store the rows you want to delete. Once you're done with the iteration you can iterate on the temporary list and remove what you decided you don't want anymore.
var toRemove = new List<DataRow>();
foreach (DataRow row in dt.Rows)
{
//call search function to look for keyword
List<int> myPages = new List<int>();
string fileName = row["linkToPublicationPDF"].ToString();
myPages = ReadPdfFile(fileName, safeKeyword);
if (myPages.Count > 0)
{
string pagelist = "";
foreach (int page in myPages)
{
pagelist = pagelist + page + " ";
}
row["Pages"] = pagelist;
}
else
{
//remove/delete the row from the datatable if "myPages.Count" is 0
toRemove.Add(row);
}
}
}
foreach (DataRow row toRemove.Add)
{
dt.Rows.Remove(row);
}
try a simple Delete
row.Delete();
then after the loop
dt.AcceptChanges();
but it will probably fail
see answer from mario
it may work if it is really only marking the row for deletion
I have many checkbox lists for searching, but when I will search by any of the checkbox list search if any record will be two times in table means will not fill into gridview.
This line of code is not allowed duplicate values, if duplicate means allow single record.
if (newdt.TableName == dt.TableName) {
// see if filter is already present in the dataset
tableMatchFound = true;
// when the current filter is already present in the dataset
foreach (DataRow dr in dt.Rows)
ds.Tables[newdt.TableName].ImportRow(dr);
}
// importrow() adds distinct new subfilters to the existing filter, duplicate items are not added
if (!tableMatchFound)
ds.Tables.Add(dt);
Below is my full .cs code.
private DataTable list(String dbObject, String filterName, String filterValue,string PositonId,string Status) {
NameValuePairList objNameValuePairList = new NameValuePairList();
objNameValuePairList.Add(new NameValuePair("#FilterValue", filterValue, PositonId, Status));
objNameValuePairList.Add(new NameValuePair("#Action", "FilterBy" + filterName, PositonId, Status));
DataTable dt = dl.Search_RegisterationInfo(dbObject, objNameValuePairList, PositonId, Status);
return dt;
}
public DataTable list(String dbOject, FilterList myFilterList,string PositonId,string Status) {
// gets a collection(dataset) of all unique filters(datatables) and also group all subfilters(rows) under each filter
DataTable dt;
DataSet ds = new DataSet();
// a filter may be a Nationality or a Qualification
foreach (Filter item in myFilterList)
// a subfilter may be Indian or Expatriate under the filter Nationality
{
// another subfilter may be Bachelor degree or Master Degree under the filter Qualification
dt = list(dbOject, item.getFilterName, item.getFilterValue, PositonId,Status);
dt.TableName = item.getFilterName;
// datatables are named based on the filters
if (ds.Tables.Count == 0)
// so we get a collection of unique filters (datatables) in the dataset
ds.Tables.Add(dt);
// add new filter without checking, since for the first time, no conflicts are possible
else
{
bool tableMatchFound = false;
foreach (DataTable newdt in ds.Tables)
if (newdt.TableName == dt.TableName)
{
// see if filter is already present in the dataset
tableMatchFound = true;
// when the current filter is already present in the dataset
foreach (DataRow dr in dt.Rows)
ds.Tables[newdt.TableName].ImportRow(dr);
}
// importrow() adds distinct new subfilters to the existing filter, duplicate items are not added
if (!tableMatchFound)
ds.Tables.Add(dt);
}
// if the filter does not exist, add the new filter to the collection
}
// the entire collection of filters will contain duplicate items
// distinct items from the entire collection is filtered out in the next section
dt = ds.Tables[0].Clone();
// get the structure of the first filter as they all apply to the same table object
if (ds.Tables.Count == 1)
dt = ds.Tables[0];
// if there is only one filter, no filtering is required
else
// if there are more than one, compare each subfilter of every other filter with the subfilters of the first filter
foreach (DataRow dr in ds.Tables[0].Rows)
{
// each subfilter from the first filter is used as a pivot
int rowMatchFound = 1;
for (int i = 1; i < ds.Tables.Count; i++)
// search all filters except the first one
foreach (DataRow newdr in ds.Tables[i].Rows)
// select each subfilter from all the filter
if ((int)dr["RegistrationId"] == (int)newdr["RegistrationId"])
rowMatchFound++;
if (rowMatchFound == ds.Tables.Count)
// a match is found exactly once in all the filters
dt.ImportRow(dr);
// the final item is selected so that is is present in all the filters
}
return dt;
}
Please follow the link for more details of my question.
https://forums.asp.net/t/2078301.aspx?Duplicate+items+are+not+added+using+ASP+NET+C+
Okay , below is the code for populating menu items dynamically from a database table.
now what i want to do is to save the "PageHeader" from the database into sessions states so that i can use those session values to check the authorization of a user on Page-load of different content pages.
now since every user have different no. of authorized pages so the no. of sessions will vary from user to user. the values of those sessions will be matched with a PageHeader variable on the Page-Load of content pages.
can someone help me how to go about it.
also i want to change the style of the menu-bar which is otherwise
default and very simple.
private void GetMenu()
{
DataTable dt = new DataTable();
dt = bll.master_Menu_Bar(en);
DataRow[] drow = dt.Select();
foreach (DataRow dr in drow)
{
MenuBar.Items.Add(new MenuItem(dr["PageHeader"].ToString(), dr["PageId"].ToString(), "", dr["PageUrl"].ToString()));
}
business logic layer method used in above code is:
public DataTable master_Menu_Bar(EntityLayer.Entity en)
{
return dll.ReturnSingleTable("Select PageHeader,PageUrl from authorized_view where Emp_Mobile="+ en.cal_EmpMobile);
}
you can make a list of string and put your menu items in there, then put that string list in session
later retrieve from the session only.
foreach (DataRow dr in drow)
{
//add items to list here
}
//make menu from that list
//put that in session or view state
Updated
How to make it store Page Id, Page Url, and Page headers
First we declare a class
public Class MenuHelper
{
public String PageId {get; set;}
public String PageHeader {get; set;}
public String PageUrl {get; set;}
}
The how we do it
List menulist = new List();
DataTable dt = new DataTable();
dt = bll.master_Menu_Bar(en);
DataRow[] drow = dt.Select();
foreach (DataRow dr in drow)
{
MenuHelper helperItem = new MenuHelper();
helperItem.PageId = dr["PageId"].ToString();
helperItem.PageHeader = dr["PageHeader"].ToString();
helperItem.PageUrl = dr["PageUrl"].ToString();
//can add menu here or not
MenuBar.Items.Add(new MenuItem(dr["PageHeader"].ToString(), dr["PageId"].ToString(), "", dr["PageUrl"].ToString()));
//Add items to list
menulist.Add(helperItem);
}
//Add list to session or view state
Session["MenuItems"] = menulist;
//When retrieving list do like this
List<MenuHelper> menulist = (List<MenuHelper>)Session["MenuItems"];
here is my simple code which does the thing ..
private void GetMenu()
{
//fetches data from business logic layer
DataTable dt1 = new DataTable();
dt1 = bll.Master_Menu_Bar(en);
//session so that the masterpage doesnt interact with database on everypostback
Session["dataTable"] = dt1;
DataTable dt=new DataTable();
dt=(DataTable)Session["dataTable"];
//session for page id's of the menuitems which will be checked for authorization at page loads of every page.
int i = 0;
while (i < dt.Rows.Count)
{
int[] PageId = new int[dt.Rows.Count];
PageId[i] = Convert.ToInt32(dt.Rows[i][2]);
Session["PageId" + i] = PageId[i];
i++;
}
//A session to keep count of the no. of menu items , this session is also used at page loads of pages as condition of if statement
Session["count"] = dt.Rows.Count;
DataRow[] drow = dt.Select();
foreach (DataRow dr in drow)
{
MenuBar.Items.Add(new MenuItem(dr["PageHeader"].ToString(), dr["PageId"].ToString(), "", dr["PageUrl"].ToString()));
}
I have two tables in database in relation 1:N and I want to populate treeview with data. The problem is how to add childs to each parent. This is my code:
private void PopulateTreeView()
{
try
{
DataTable dtProjekti = objDB.dbGetTable("SELECT * FROM tblProjekti");
DataTable dtAktivnosti = objDB.dbGetTable("SELECT * FROM tblprojektakt");
DataSet ds = new DataSet();
ds.Tables.Add(dtProjekti);
ds.Tables.Add(dtAktivnosti);
ds.Relations.Add("childrens", dtProjekti.Columns["OznakaProjekta"], dtAktivnosti.Columns["OznakaProjekta"]);
if (ds.Tables[0].Rows.Count > 0)
{
treeView1.Nodes.Clear();
foreach (DataRow masterRow in ds.Tables[0].Rows)
{
//TreeNode masterNode = new TreeNode((string)masterRow["ParentName"], Convert.ToString(masterRow["ParentId"]));
TreeNode masterNode = new TreeNode(masterRow["OznakaProjekta"].ToString());
treeView1.Nodes.Add(masterNode);
foreach (DataRow childRow in masterRow.GetChildRows("Children"))
{
// missing code for adding childs to each parent
}
}
}
}
catch (Exception ex)
{
throw new Exception("Unable to populate treeview" + ex.Message);
}
}
}
The childs are values from field Description.
I know how to manually add child to each parent but i stucked whan it should be dynamically.
The childs are values from field Description.
If you mean column Description. It should be something like this:
foreach (DataRow childRow in masterRow.GetChildRows("Children"))
{
masterNode.Nodes.Add(new TreeNode(childRow["Description"].ToString()));
}