I have a gridview on my webpage that can have rows added dynamically. There is a for loop that adds the rows like this:
protected void AddNewJob(object sender, EventArgs e)
{
for(int i = 0; i < Convert.ToInt32(newJobCount.Text);i++)
{
TableRow tr = new TableRow();
tr.Cells.Add(ServicesDDL("-- Select Service Type --"));
tr.Cells.Add(JobsDDL("-- Select Job Type --"));
tr.Cells.Add(TextBoxCell());
tr.Cells.Add(TextBoxCell());
tr.Cells.Add(TextBoxCell());
assetTable.Rows.Add(tr);
}
}
After the rows are added and changed from their default values the rows are looped through and data is saved to the database. I'm having problems getting the rows added to the gridview to persist and exist on the gridview when the page's save event is triggered. That code looks like this:
foreach (TableRow row in assetTable.Rows)
{
if (isFirst)
{
isFirst = false;
continue;
}
DropDownList service = (DropDownList)row.Cells[0].Controls[0];
string assetText = service.SelectedItem.Value;
DropDownList jobDescription = (DropDownList)row.Cells[1].Controls[0];
string serialText = jobDescription.SelectedItem.Value;
TextBox equipmentCount = (TextBox)row.Cells[2].Controls[0];
string leaseText = equipmentCount.Text;
TextBox jobSize = (TextBox)row.Cells[3].Controls[0];
string originText = jobSize.Text;
TextBox serialNo = (TextBox)row.Cells[4].Controls[0];
string deliveryText = serialNo.Text;
string oNo = orderNo.Text;
if (assetText != "0" && serialText != "0")
{
APICallClass.Job j = new APICallClass.Job();
j.JobTypeID = Convert.ToInt32(serialText);
j.serviceID = Convert.ToInt32(assetText);
j.equipment = leaseText;
j.jobSize = originText;
j.serialNumbers = deliveryText;
j.orderID = Convert.ToInt32(global.GlobalID);
APICallClass.API.AddJob(j, Session["Variable"].ToString());
}
}
When the code pasted above runs, it only sees the rows that are pulled in from the database. I think my problem could be fixed by calling something like .databind() somewhere that I'm not, but I've tried a few places and they have not fixed the problem.
Thanks in advance for any help, and helping me become a more robust ASP.NET developer.
When a GridView is DataBind()-ed, the contents of the GridView are "rebuilt" based on the the GridView's DataSource. If you need the new row to stay in the GridView, either do not call DataBind() after the new row is added, or ensure that the contents of your new row are in the GridView's DataSource before future calls to DataBind().
In a page I wrote once I had a similar situation and did the latter. The data for the initial rows was pulled from the database on the first page load and persisted in ViewState. As the user added, removed, and reordered rows in the GridView, the page just changed the data in ViewState and re-DataBind()ed the GridView.
Related
i have a dropDownList which gets its data from a database. Now after the data has bound, i programmatically add another listItem to the ddl, like so:
protected void ddlEffects_DataBound(object sender, EventArgs e)
{
DropDownList ddl = dwNewItem.FindControl("ddlEffects") as DropDownList;
ddl.Items.Add(new ListItem("","0")); //Adds an empty item so the user can select it and the item doesnt provide an effect
}
It all works, but the problem is that the newly added listItem appears at the bottom of the DDL. I want it to be the first item. I tried making the value 0, but its still at the bottom. Is there any way to put it at the top?
Thanks!
Check into the ddl.Items.Insert method that will allow you to insert items at a specific location.
Like this for example:
using (Entities db = new Entities())
{
ddlDocumentTypes.DataSource = (from q in db.zDocumentTypes where (q.Active == true) select q);
ddlDocumentTypes.DataValueField = "Code";
ddlDocumentTypes.DataTextField = "Description";
ddlDocumentTypes.DataBind();
ddlDocumentTypes.Items.Insert(0, "--Select--");
ddlDocumentTypes.Items[0].Value = "0";
}
Which using EF loads the DDL with items for the database, and then inserts at position zero a new item.
I have a GridView and I populate it via a List . One of its columns is a DropDownList and AllowPaging is set to true. My problem is when I choose a value on the ddl and after a paging the selected value is lost. Is there any way/idea to persist the selected values?
Thanks for your help.
You could use a Dictionary object within view state to save multiple values i.e.
Dictionary<int, string> ddlValues = new Dictionary<int, string>()
where int is the row index and string is the ddl selected value. Of course this could be an int/guid or whatever depending on the actual value stored in the ddl or an int if you want to work with selectedIndex instead.
on the page event you would need to do
protected void MyGridView_PageIndexChanging(Object sender, GridViewPageEventArgs e)
{
for(int rowIndex = 0; rowIndex < myGridView.Rows.Length; rowIndex++)
{
DropdownList ddl = myGridView.Rows[rowIndex].FindControl("ddlId") as DropDownList
if(ddl != null)
{
if(ddl.SelectedIndex > 0) //.. or sensible check appropriate to you
{
int ddlIndex = rowIndex * e.NewPageIndex + 1;
//.. add pageIndex and selectedValue to dictionary
ddlValues.Add(ddlIndex, ddl.SelectedValue);
}
}
}
}
Don't worry about the current page ddl values. These will be persisted with viewstate in the normal way. It is the 'hidden' pages that we are accounting for. Hence we are repopulating the dictionary when the grid pages.
The Dictionary could then be saved in session/viewState and used to rehydrate the dropdownlist by doing the process in reverse. For instance when the page loads (checking !isPostBack) or when the grid rebinds depending on exactly how you have set things up
You will probably want to persist the Data in the ViewState. Check out this MSDN article
http://msdn.microsoft.com/en-us/library/ms972976.aspx
After you save it in the ViewState, you can retrieve the data on PostBack like this:
if (!Page.IsPostBack)
{
//do some stuff
}
else
{
//retrieve the viewstate information
selectedValue= ViewState["dropdownlistValue"].ToString();
}
Alternatively, you could also maintain the information in a Session variable but that may introduce other issues depending on what exactly you are doing.
My project has a GridView to display some information. That GridView has some OnRowDataBound processing to massage the data. What I'm trying to do is copy the resulting GridView into a DataTable so I can generate a CSV file. The CSV is generated when the user clicks a button. So the GridView is on the screen and populated and a PostBack occurs. The GridView is not being re-bound on PostBack. What is the recommended way to do this? Here is the code I'm trying currently but I just end up with the headings and blank rows. Debugging confirms that row.Cells[i].Text is empty even though the heading is correct and there is the same number of rows as my GridView contained.
DataTable dataTable = new DataTable("export");
foreach (DataControlField column in myGV.Columns)
{
dataTable.Columns.Add(new DataColumn { ColumnName = column.HeaderText });
}
foreach (GridViewRow row in myGV.Rows)
{
DataRow dataRow = dataTable.NewRow();
for (int i = 0; i < row.Cells.Count; i++)
{
dataRow[myGV.Columns[i].HeaderText] = row.Cells[i].Text;
}
}
You need to work with the data object you're binding to the GridView, not the gridview. There is no hook to the data in the gridview after binding.
I have got 2 DropDownLists on my Form and 1 GridView. I want the GridView to display the data according to the selection from the DropDownLists.
For Example, One DropDownList contains Names and another contains Dates. Both the DropDownLists can post back. So if I select a name from 1st DropDownList, the GridView should show all the results according to that Name. Similarly if i select the Date from the other DropDownList , the GridView should show the results according to the dates. But i cant figure out as how to bind GridView to respond to 2 DropDownList.
BTW i am binding both the Drop Down Lists and the Grid View to the DataSource Objects, which is getting data from the database.
Any Suggestions??
It's better and cleaner if You use two DataSource with selecting data from db, and binding each of them to the DropDownList. I tried in my ASP.NET app do what You want but unfortunatelly I have erorrs :/
My only sollution is to don't use DataSouce in aspx file, but in DropDownList SelectedItem event use DataContext and it's possible that then you could bind both to the same DataView like below. I am not sure, but maybe You must use null in DataSource to reset GridView before use new data source:
protected void btPokaz_Click(object sender, EventArgs e)
{
DataClassesDataContext db = new DataClassesDataContext();
var DzieciGrupa = from p in db.Dzieckos
where p.Grupy.Numer == Convert.ToInt32(this.dropListGrupy.SelectedValue)
orderby p.Nazwisko
select new { p.Imie, p.Nazwisko };
if (DzieciGrupa.Count() == 0) this.Label1.Text = "W " + this.dropListGrupy.SelectedValue.ToString() + " grupie nie ma dzieci zapisanych!";
this.GridGrupy.DataSource = null;
this.GridGrupy.DataSource = DzieciGrupa;
// this.GridView1.DataSourceID = String.Empty;
this.GridGrupy.DataBind();
Try it and tell say that works ;)
For Your problem You should create dwo EDM class for each data source. And simple in DDL select event Your choose of DataContext depends from user choose in DDL.
Example :
protected void DDL_SelectedItem(object sender, EventArgs e)
{
TypeOfQueryData query = null;//you must know what type is data You query
if(this.dropListGrupy.SelectedValue==someItemSelect)
{
DataClasses1DataContext db = new DataClasses1DataContext();
//query to get data from source
query= from p in db.Dzieckos
where p.Grupy.Numer == Convert.ToInt32(this.dropListGrupy.SelectedValue)
orderby p.Nazwisko
select new { p.Imie, p.Nazwisko };
}
if(this.dropListGrupy.SelectedValue==otherItemSelect)
{
DataClasses2DataContext db = new DataClasses2DataContext();
query= from p in db.Dzieckos
where p.Grupy.Numer == Convert.ToInt32(this.dropListGrupy.SelectedValue)
orderby p.Nazwisko
select new { p.Imie, p.Nazwisko };
}
this.GridGrupy.DataSource = null;
this.GridGrupy.DataSource = DzieciGrupa;
// this.GridView1.DataSourceID = String.Empty;//maybe You need do that
this.GridGrupy.DataBind();
I have a gridview (actually a SPgridview)
And i made the columnname clickable so the users can sort the rows using the data.
And that works fine.
The problem occurs when users try to select a row after they sorted the data.
I can see that the gridview kinda "forgets" how the rows were sorted and selects the row that was at the clicked index before it got sorted..
How do i fix that?
I tried sorting the row again after the user selects a row, but that doesnt seem to work.
And should the gridview remember the fact that it was just sorted?
Thanks in advance :)
When you handle the Sorting event set a session variable set it to the sort direction and use it when you rebind your datasource.
protected void gridview_Sorting()
{
// BIND DATA Function
BindData();
DataTable dt = gridview.DataSource as DataTable;
if (dt != null)
{
//Sort the data.
dt.DefaultView.Sort = e.SortExpression + " " + GetSortDirection(e.SortExpression);
Session["sort"] = dt.DefaultView.Sort;
gridview.DataSource = dt;
gridview.DataBind();
}
}
// bind data function//
private void BindData()
{
DataTable dt = GetDataTable();
if (Session["sort"] != null)
{
//Sort the data.
dt.DefaultView.Sort = Session["sort"].ToString();
}
gridview.DataSource = dt;
gridview.DataBind();
}
Make sure that you are not rebinding the grid after a postback.
if(!IsPostBack)
{
gridView.DataSource = yourDataSource;
gridView.DataBind();
}
Are you grabbing the selected row by it's row index or by the unique identifier of the data you are wanting to edit? If you're getting by row index, it may be 'forgetting' since you are recreating the Grid on OnPostBack. Try iterating through the data and select it by it's unique ID, not its row index.
Check Johans blog regarding SPGridView and LinqDataSource
I'd made a number of sortable GridViews, but none with row command interaction before today, when I stumbled on this problem. Mine is a "plain" GridView, not SPgridview. I found this works:
In bindData(), if we have not created a DataTable and put it in the Session object, do so. Otherwise, we'll use the existing, sorted DataTable:
if (Session["dtbl"] == null) {
Session["dtbl"] = method_to_fetch_datatable();
}
gv.DataSource = Session["dtbl"] as DataTable;
gv.DataBind();
In the GridView's handling of row commands that INSERT, UPDATE or DELETE underlying data, refresh the Session object, maintaining the sort, if there is one:
Session["dtbl"] = method_to_fetch_datatable();
if (ViewState["SortExpression"] != null) {
DataTable dt = Session["dtbl"] as DataTable;
dt.DefaultView.Sort = ViewState["SortExpression"] as string;
}
bindData();
I got it working. (kinda)
In the sorting event i saved the sortexpression (the name of the column used to sort by)
and the sortdirection ascending or descending.
Then i make the datasource for the gridview and databind, and after databinding it, i use the gridview.sort command to sort by the values i saved in viewstate.
That works fine, only one problem.
When sorting i made it switch direction after pressing the same column more than one time.
Now it thinks i keep pressing the column title, so it keeps reversing the sorting.
But i tempererarely made it only sort in one direction.
And now im playing with the sender object in the sorting event, im thinking that if i could get some info about whats causing the event i could tell it to only switch direction based on the sender.
Thanks :)