persist dropdownlist on paging - asp.net

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.

Related

Rows added to gridview don't persist when save event is triggered

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.

Sorting a gridview using a datatable, and datasource that is an ArrayList

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.sorting.aspx
This article deals with creating a datatable first, then creating a gridview from it, to aid in sorting. My predicament is slightly different.
I have a Gridview, that on Page_Load, I set the datasource to an ArrayList, and bind.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
this.GridView1.DataSource = RequestManager.Instance.GetAllRequests();
this.GridView1.DataBind();
}
}
Now I would like to sort this GridView, so on the aspx page, I set AllowSorting="true", and OnSorting="GridView1_Sorting". So far, so good. I have the SortExpressions set in the BoundFields, and when I click on it, I know the _Sorting event is triggered.
Now, since this is a postback operation, I cannot simply cast the datasource of the gridview to a DataTable to sort. Saving to ViewState is an option, but I cannot figure out how to do it.
I would like to use the simple solution on this page, except for the DataTable not being available to me. Thanks for looking.
If you're able to target .NET v3.5, I recommend using Linq. In your _Sorting event handler, get the array list you did in the Page_Load and rebind it.
For example, if the type contained in the array list are MyType instances that have properties named Default and SomeField:
protected void Grid_Sorting(object sender, GridViewSortEventArgs e)
{
Func<MyType, object> keySelector;
if(e.SortExpresion == "SomeField")
{
keySelector = dataItem => dataItem.SomeField;
}
else
{
keySelector = dataItem => dataItem.Default;
}
ArrayList dataItems = RequestManager.Instance.GetAllRequests();
this.GridView1.DataSource = dataItems.OfType<MyType>().OrderBy(keySelector);
this.GridView1.DataBind();
}
That will get you started, then later inspect the sort expression to see if it ends with ASC or DESC and conditionally call .OrderByDescending(keySelector).
Finally, I don't recommend stashing the list in ViewState, as the ObjectStateFormatter is only optimized for a handful of types. http://msdn.microsoft.com/en-us/library/system.web.ui.objectstateformatter.aspx
Maybe consider ASP.NET cache instead.

Dynamically update dropdownlist

I have this dropdownlist populated and everything. The only problem is that whenever I add a new item in the database through my website, the dropdownlist doesn't update for some reason.
private CurrentUser _cu = new CurrentUser();//just to check if use is an admin or not.
protected void Page_Load(object sender, EventArgs e)
{
_cu = (CurrentUser)Session[Common.SessVariables.CurUser];
if (!_cu.CanReport) { Response.Redirect("~/default.aspx"); }
CurrentUser cu = (CurrentUser)Session[Common.SessVariables.CurUser];
if (!IsPostBack)
{
foreach (PrefixAdd loc in cu.Prefix)//Prefix is a Property
{
ListItem x = new ListItem(loc.Prefix);
PrefixID.Items.Add(x);
}
}
}
#Wayne I'm using a store procedure to just insert a Prefix like Pre,yes,sey, etc. Then the list is populated with prefixes.
StringBuilder sbSQL = new StringBuilder(255);
sbSQL.Append(string.Format("exec insPrefix #Prefix=N'{0}';", PrefixBox.Text.Trim()));
string msg = string.Empty;
msg = (_oDAW.ExecuteNonQuery(sbSQL.ToString())) ? string.Format(Common.GetAppSetting(Common.ConfigKeys.User_Submit_Success),
PrefixBox.Text.Trim()) : Common.GetAppSetting(Common.ConfigKeys.SubmitFail); //this is a somewhat custom method for CS and databinding.
# Yuriy Rozhovetskiy Yea I add new items to this page with the dropdownlist.
Whenever you add an item to your database, you have to rebind your drop down list.
yourDropDown.DataSource = //...
yourDropDown.DataBind();
That is, DropDownLists (and other controls) have no way of knowing that their data has changed behind the scenes, they can't automatically detect it. You have to tell the controls to rebind their data manually.
Good job on the Page_Load(...){ if !(IsPostback) part.
Since you add new prefix on this page with some postback item you need to add this new item to PrefixID dropdown's Items collection and update the CurrentUser instance in Session right after you have add new prefix to database.

Making GridView Respond to 2 Drop Down Lists

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();

ASP.net list of dropdownlists - similar to Access continuous form

What I'm looking for is a way to mimic the MS-Access style continuous form within asp.net. In one particular case, I want a control, bound to a datasource which returns a dropdownlist for each row, bound to the value within the datasource. Any change to any of the dropdownlists' would perform an update to the database instantly.
I have got halfway to achieving this using a repeater control, with the DropDownList.SelectedValue assigned within the Repeater.ItemDataBound event.
But now, supposing I add an OnSelectedIndexChanged event to the DropDownList - how would I then query the repeater to know which row I was on (to get the primary key value, for example)
I'm not sure this can be done easily.. so the question is what should I really be doing? I don't want to use a GridView that requires me to select a row to edit.. I just want to have the dropdownlists autopostback for any updates.
Hope that's clear?!
Cheers! :D
For examples sake, lets say we are binding to a custom class called Record
public class Record
{
public int Id;
public string Value;
}
If you put custom logic on the Repeater.OnItemCreated event you can attach the primary key to the id of the drop down list
protected void Repeater_ItemCreated(object sender, RepeaterItemEventArgs e)
{
if (!(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem))
return;
var dataItem = e.Item.DataItem as Record;
if (dataItem == null) return;
var dropdown = e.Item.FindControl("myDropDown") as DropDownList;
if (dropdown == null) return;
dropdown.ID = dropdown.ID + dataItem.Id;
}
Then on the SelectedIndexChange, you can pull the id off of the dropdown that fired the event.
protected void SelectedIndexChanged(object sender, EventArgs e)
{
var dropdown = sender as DropDownList;
if (dropdown == null) return;
var stringId = dropdown.ID.Replace("myDropDown", "");
int id;
if (Int32.TryParse(stringId, out id))
{
updateRecord(id, dropdown.SelectedValue);
}
}
It's very much an ugly hack, but it should allow you to do what you want.
Easiest way to tackle this would be to mimic the Access continuous form ASP.NET style. Which would be to make a UserControl to handle the row-level UI, then put said UserControl in a repeater.

Resources