Dynamically Generated Dropdowns Postback - c#

I'm having some trouble with same Dynamically generated dropdowns and their viewstate.
Long story short, a user will upload an excel file, the file will get parsed and the dropdowns will be created for the appropriate data. This is done on when an asp button is pressed, and the controls are added to a table as follows:
public void generateFromSheet(OrderedDictionary columns, DataTable oppcolumns, List<string> requiredDrops)
{
int index = 0;
foreach (DictionaryEntry entry in columns)
{
DropDownList ddl = new DropDownList()
{
ID = "ddlMapping" + entry.Key.ToString(),
DataSource = columns,
DataTextField = "Key",
DataValueField = "Value",
SelectedIndex = index,
Enabled = requiredDrops.Contains(entry.Key) ? false : true
};
ddl.DataBind();
DropDownList ddl2 = new DropDownList()
{
ID = "OpportunityMappingDdl" + index,
DataSource = oppcolumns,
DataTextField = "AttributeDisplayName",
DataValueField = "TableColumnName"
};
ddl2.DataBind();
HtmlTableCell td = new HtmlTableCell()
{
ID = "tdMapping" + index
};
td.Controls.Add(ddl);
HtmlTableCell td2 = new HtmlTableCell()
{
ID = "tdOppMapping" + index
};
td2.Controls.Add(ddl2);
HtmlTableRow tr = new HtmlTableRow()
{
ID = "trMapping" + index
};
tr.Cells.Add(td);
tr.Cells.Add(td2);
tblFileMapping.Rows.Add(tr);
index++;
}
}
However, on each postback after this, the drop-downs are erased. I've looked online for a solution and usually everything points to recreating the controls using the same id's as when they were created so that their state can be restored from ViewState. I've tried that as follows below by storing what I should create in ViewState:
public void generateFromViewState()
{
OrderedDictionary columns = (OrderedDictionary) ViewState["XLColumns"];
int index = 0;
foreach (DictionaryEntry entry in columns)
{
DropDownList ddl = new DropDownList()
{
ID = "ddlMapping" + entry.Key.ToString(),
};
DropDownList ddl2 = new DropDownList()
{
ID = "OpportunityMappingDdl" + index,
};
HtmlTableCell td = new HtmlTableCell()
{
ID = "tdMapping" + index
};
td.Controls.Add(ddl);
HtmlTableCell td2 = new HtmlTableCell()
{
ID = "tdOppMapping" + index
};
td2.Controls.Add(ddl2);
HtmlTableRow tr = new HtmlTableRow()
{
ID = "trMapping" + index
};
tr.Cells.Add(td);
tr.Cells.Add(td2);
tblFileMapping.Rows.Add(tr);
index++;
}
}
I call this method in the page_load but the controls do not retain their previous data and selected values.
So a couple of things wrong here:
On page_load the controls are recreated but their state is not restored.
For some technical reasons, my Project Manager mentioned I should not use the Session State to store anything.
Another PM advised me that the controls should be regenerated on page_init. BUT since I'm storing the control data in ViewState, this isn't possible because the viewstate isnt ready and my data is null.
Can anyone advise on how to succesfully restore the viewstate for these dynamically generated controls. I've tried searching everything and tried a bunch of solutions online, but nothing I have tried seems to work.
Thanks!

You are doing it right, but you have to recreate the controls with datasource and rebinding all controls again. Without this beeing done, you are creating controls that not match the previous. You can call your first method to do that.

Related

FocusedRowHandle not setting correctly in a DevExpress GridView C#

I am trying to update my GridView to auto select a new row that is added after the user fills out the fields and presses add. However, I am having no luck when trying to set the FocusedRowHandle property. The FocusedRowHandle value stays at -2147483648 even after I try to assign a value to it as shown in the following code:
private void gvExample_RowUpdated(object sender, RowObjectEventArgs e)
{
try
{
ExampleMethodToUpdateTableAdapter();
GridView view = sender as GridView;
Object obj;
if (e.RowHandle != GridControl.NewItemRowHandle)
obj = view.GetRow(view.FocusedRowHandle);
else
{
dsExample.dtExample.DefaultView.Sort = "ID desc";
DataTable dtSorted = dsExample.dtExample.DefaultView.ToTable(true);
int lastID = Convert.ToInt32(dtSorted.Rows[0]["ID"]);
gvExample.FocusedRowHandle = lastID;
}
}
catch (Exception ex)
{
}
}
When stepping into the else statement the aim was to get the latest ID from the DataTable now it has been updated (since the value at e.RowHandle is -2147483648 because its a new row) and set the Focused Row to this ID.
I have tried to have a look online for this but can't seem to find a solution so I thought I'd have a go at posting on here. Apologies if I've missed any info out.
If i understand correct you want to focus the new row (which is the last row):
gridView.FocusedRowHandle = gridView.RowCount - 1;
If not, you have to search the id inside the gridvw with for i 0-> gridView.RowCount - 1 and then when you will find the Id to focus the row with the i value.
for (int i = 0; i <= gridView.RowCount - 1; i++)
{
if (gridView.GetRowCellValue(i, gridView.columns(column_number)))
{
gridView.FocusedRowHandle = i;
}
}

DataGrid generating blank rows

I am populating a DataTable with some values (after defining the column names) and then using it as a data source for a Sage Grid - functionally very similar to a WinForms DataGridView.
So far, I have tried adding the data type to the DataTable columns and populating a BindingSource with the DataTable and then binding it to the Sage Grid. When viewing the contents of the DataTable whilst debugging you can see the data is there using DataSet Visualiser.
Creating the DataTable -
DataTable failedOrders = new DataTable();
failedOrders.Columns.Add("externalItemCodeColumn", typeof(String));
failedOrders.Columns.Add("reasonColumn", typeof(String));
foreach (String item in insufficientItemsAvailable)
{
DataRow dataRow = failedOrders.NewRow();
dataRow["externalItemCodeColumn"] = item;
dataRow["reasonColumn"] = "Not enough available items in WAREHOUSE";
failedOrders.Rows.Add(dataRow);
}
Populating the Sage Grid -
Sage.Common.Controls.GridColumn externalItemCodeColumn = new Sage.Common.Controls.GridColumn();
externalItemCodeColumn.Caption = "External Item Code";
externalItemCodeColumn.DisplayMember = "externalItemCodeColumn";
Sage.Common.Controls.GridColumn reasonColumn = new Sage.Common.Controls.GridColumn();
reasonColumn.Caption = "Reason";
reasonColumn.DisplayMember = "reasonColumn";
failedOrdersGrid.Columns.Add(externalItemCodeColumn);
failedOrdersGrid.Columns.Add(reasonColumn);
failedOrdersGrid.DataSource = FailedOrders;
//failedOrdersGrid.Refresh(); - this doesn't seem to make a difference
Please note that failedOrders is passed to another method hence the name change from failedOrders to FailedOrders.
Just to check that this behaviour is not specific to the Sage Grid, I tried populating a regular WinForms DGV with the DataTable. (Note - I disabled AutoGenerateColumns as this does not seem to be an option for the Sage Grid).
dataGridView1.AutoGenerateColumns = false;
dataGridView1.Columns.Add("externalItemCodeColumn", "External Item Code");
dataGridView1.Columns.Add("reasonColumn", "Reason");
dataGridView1.DataSource = FailedOrders;
I expect the contents of the Sage Grid to match those of the DataGrid, but instead get blank rows.
The Sage.Common.Controls.Grid inherits from the Sage.Common.Controls.List and the DataSource property of Sage.Common.Controls.List requires on refresh that the new DataSource supports at least IList
(It literally just nulls out your datasource if it isn't an IList)
Here's an adaptation of your code to work with the Sage.Common.Controls.Grid
I added this to the constructor of my form (where failedOrdersGrid is of type Sage.Common.Controls.Grid):
List<Failure> failedOrders = new List<Failure>();
foreach (String item in new List<string> { "1", "2", "3" })
{
failedOrders.Add(new Failure { externalItemCodeColumn = item, reasonColumn = "Not enough available items in WAREHOUSE" });
}
Sage.Common.Controls.GridColumn externalItemCodeColumn = new Sage.Common.Controls.GridColumn();
externalItemCodeColumn.Caption = "External Item Code";
externalItemCodeColumn.DisplayMember = "externalItemCodeColumn";
Sage.Common.Controls.GridColumn reasonColumn = new Sage.Common.Controls.GridColumn();
reasonColumn.Caption = "Reason";
reasonColumn.DisplayMember = "reasonColumn";
failedOrdersGrid.Columns.Add(externalItemCodeColumn);
failedOrdersGrid.Columns.Add(reasonColumn);
failedOrdersGrid.DataSource = failedOrders;
And here's the failure class:
public class Failure
{
public string externalItemCodeColumn { get; set; }
public string reasonColumn { get; set; }
}

Selecting the shortest item string from dropdownlist in C# Asp.net

I have multiple dynamically generated dropdownlists bound with database. I want the shortest string value to be shown at index 0 in each dropdown.
The sample code is:
DropDownList ddlTemplate = new DropDownList();
ddlTemplate.ID = "ddlTemplate|" + j.ToString();
ddlTemplate.AppendDataBoundItems = true;
ddlTemplate.DataTextField = "TemplateName";
ddlTemplate.DataValueField = "TemplateName";
ddlTemplate.Width = Unit.Pixel(200);
ddlTemplate.AutoPostBack = true;
ddlTemplate.DataSource = null;
ddlTemplate.DataSource = dsMultipleTemplate.Tables[j].DefaultView;
ddlTemplate.DataBind();
If it can be achieved through database query please guide me.
Thanks
As you arnt answering to the comment, maybe you are looking for something like that:
List<int> stringLength = new List<int> { }; // storing every length
foreach (string entry in ddlTemplate.Items)
{
stringLength.Add(entry.Length); // saving each string-length
}
int index = stringLength.FindIndex(a => a == stringLength.Min()); // get index of lowst length
ddlTemplate.SelectedIndex = index; // set selected value to index from above
This way, your item wouldnt be at index 0, but it would be selected. Placing it to index 0 is very basic. I guess you can do this on your own.

empty row Repeater dynamically

public static void ShowNoResultFoundGridWiew<T>(List<T> source, GridView gv, string text) where T : new()
{
if (source == null)
return;
source.Add(new T());
gv.DataSource = source;
gv.DataBind();
// Get the total number of columns in the GridView to know what the Column Span should be
int columnsCount = gv.Columns.Count;
gv.Rows[0].Cells.Clear(); // clear all the cells in the row
gv.Rows[0].Cells.Add(new TableCell()); //add a new blank cell
gv.Rows[0].Cells[0].ColumnSpan = columnsCount; //set the column span to the new added cell
// You can set the styles here
////gv.Rows[0].Cells[0].HorizontalAlign = HorizontalAlign.Center;
////gv.Rows[0].Cells[0].ForeColor = System.Drawing.Color.Red;
////gv.Rows[0].Cells[0].Font.Bold = true;
// Or you can pass a css class name
//gv.Rows[0].Cells[0].CssClass = "EmptyDataRowStyle";
gv.Rows[0].Cells[0].Text = text;
}
How can i create in the sam way empty row for repeater? Is it possible. I do not know how to add row and clear it...
Repeaters aren't guaranteed to contain rows and columns: they can have any internal structure (or no structure), so you can't do the same thing.
You're probably better off hiding the repeater and showing an entirely different control when your data source has no items, like an HTML literal.

Sorting a DropDownList? - C#, ASP.NET

I'm curious as to the best route (more looking towards simplicity, not speed or efficiency) to sort a DropDownList in C#/ASP.NET - I've looked at a few recommendations but they aren't clicking well with me.
Edit: Folks, I do not have control over how the data comes into the DropDownList - I cannot modify the SQL.
If you get a DataTable with the data, you can create a DataView off of this and then bind the drop down list to that. Your code would look something like...
DataView dvOptions = new DataView(DataTableWithOptions);
dvOptions.Sort = "Description";
ddlOptions.DataSource = dvOptions;
ddlOptions.DataTextField = "Description";
ddlOptions.DataValueField = "Id";
ddlOptions.DataBind();
Your text field and value field options are mapped to the appropriate columnns in the data table you are receiving.
A C# solution for .NET 3.5 (needs System.Linq and System.Web.UI):
public static void ReorderAlphabetized(this DropDownList ddl)
{
List<ListItem> listCopy = new List<ListItem>();
foreach (ListItem item in ddl.Items)
listCopy.Add(item);
ddl.Items.Clear();
foreach (ListItem item in listCopy.OrderBy(item => item.Text))
ddl.Items.Add(item);
}
Call it after you've bound your dropdownlist, e.g. OnPreRender:
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
ddlMyDropDown.ReorderAlphabetized();
}
Stick it in your utility library for easy re-use.
Assuming you are running the latest version of the .Net Framework this will work:
List<string> items = GetItemsFromSomewhere();
items.Sort((x, y) => string.Compare(x, y));
DropDownListId.DataSource = items;
DropDownListId.DataBind();
DropDownList takes any IEnumerable as a DataSource.
Just sort it using LINQ.
I usually load a DropDownList with values from a database table, so the easiest way is to sort your results as desired with the ORDER BY clause of your SELECT statement, and then just iterate through the results and dump them into the DropDownList.
Take a look at the this article from CodeProject, which rearranges the content of a dropdownlist. If you are databinding, you will need to run the sorter after the data is bound to the list.
It is recommended to sort the data before databinding it to the DropDownList but in case you can not, this is how you would sort the items in the DropDownList.
First you need a comparison class
Public Class ListItemComparer
Implements IComparer(Of ListItem)
Public Function Compare(ByVal x As ListItem, ByVal y As ListItem) As Integer _
Implements IComparer(Of ListItem).Compare
Dim c As New CaseInsensitiveComparer
Return c.Compare(x.Text, y.Text)
End Function
End Class
Then you need a method that will use this Comparer to sort the DropDownList
Public Shared Sub SortDropDown(ByVal cbo As DropDownList)
Dim lstListItems As New List(Of ListItem)
For Each li As ListItem In cbo.Items
lstListItems.Add(li)
Next
lstListItems.Sort(New ListItemComparer)
cbo.Items.Clear()
cbo.Items.AddRange(lstListItems.ToArray)
End Sub
Finally, call this function with your DropDownList (after it's been databound)
SortDropDown(cboMyDropDown)
P.S. Sorry but my choice of language is VB. You can use http://converter.telerik.com/ to convert the code from VB to C#
Another option is to put the ListItems into an array and sort.
int i = 0;
string[] array = new string[items.Count];
foreach (ListItem li in dropdownlist.items)
{
array[i] = li.ToString();
i++;
}
Array.Sort(array);
dropdownlist.DataSource = array;
dropdownlist.DataBind();
I agree with sorting using ORDER BY when populating with a database query, if all you want is to sort the displayed results alphabetically. Let the database engine do the work of sorting.
However, sometimes you want some other sort order besides alphabetical. For example, you might want a logical sequence like: New, Open, In Progress, Completed, Approved, Closed. In that case, you could add a column to the database table to explicitly set the sort order. Name it something like SortOrder or DisplaySortOrder. Then, in your SQL, you'd ORDER BY the sort order field (without retrieving that field).
What kind of object are you using for databinding? Typically I use Collection<T>, List<T>, or Queue<T> (depending on circumstances). These are relatively easy to sort using a custom delegate. See MSDN documentation on the Comparison(T) delegate.
var list = ddl.Items.Cast<ListItem>().OrderBy(x => x.Text).ToList();
ddl.DataSource = list;
ddl.DataTextField = "Text";
ddl.DataValueField = "Value";
ddl.DataBind();
Try it
-------Store Procedure-----(SQL)
USE [Your Database]
GO
CRATE PROC [dbo].[GetAllDataByID]
#ID int
AS
BEGIN
SELECT * FROM Your_Table
WHERE ID=#ID
ORDER BY Your_ColumnName
END
----------Default.aspx---------
<asp:DropDownList ID="ddlYourTable" runat="server"></asp:DropDownList>
---------Default.aspx.cs-------
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
List<YourTable> table= new List<YourTable>();
YourtableRepository tableRepo = new YourtableRepository();
int conuntryInfoID=1;
table= tableRepo.GetAllDataByID(ID);
ddlYourTable.DataSource = stateInfo;
ddlYourTable.DataTextField = "Your_ColumnName";
ddlYourTable.DataValueField = "ID";
ddlYourTable.DataBind();
}
}
-------LINQ Helper Class----
public class TableRepository
{
string connstr;
public TableRepository()
{
connstr = Settings.Default.YourTableConnectionString.ToString();
}
public List<YourTable> GetAllDataByID(int ID)
{
List<YourTable> table= new List<YourTable>();
using (YourTableDBDataContext dc = new YourTableDBDataContext ())
{
table= dc.GetAllDataByID(ID).ToList();
}
return table;
}
}
I agree with the folks in sorting your data in the model before populating them to the DropDownList, so if you are populating this from a DB, it is a good thing to get them sorted already there using a simple order by clause, it will save you some cycles in the web server, and I am sure the DB will do it so much faster.
If you are populating this from another data source for example, XML file, using LINQ will be a good idea, or even any variation of Array.Sort will be good.
If your data is coming to you as a System.Data.DataTable, call the DataTable's .Select() method, passing in "" for the filterExpression and "COLUMN1 ASC" (or whatever column you want to sort by) for the sort. This will return an array of DataRow objects, sorted as specified, that you can then iterate through and dump into the DropDownList.
List<ListItem> li = new List<ListItem>();
foreach (ListItem list in DropDownList1.Items)
{
li.Add(list);
}
li.Sort((x, y) => string.Compare(x.Text, y.Text));
DropDownList1.Items.Clear();
DropDownList1.DataSource = li;
DropDownList1.DataTextField = "Text";
DropDownList1.DataValueField = "Value";
DropDownList1.DataBind();
To sort an object datasource that returns a dataset you use the Sort property of the control.
Example usage In the aspx page to sort by ascending order of ColumnName
<asp:ObjectDataSource ID="dsData" runat="server" TableName="Data"
Sort="ColumnName ASC" />
is better if you sort the Source before Binding it to DropDwonList.
but sort DropDownList.Items like this:
Dim Lista_Items = New List(Of ListItem)
For Each item As ListItem In ddl.Items
Lista_Items.Add(item)
Next
Lista_Items.Sort(Function(x, y) String.Compare(x.Text, y.Text))
ddl.Items.Clear()
ddl.Items.AddRange(Lista_Items.ToArray())
(this case i sort by a string(the item's text), it could be the suplier's name, supplier's id)
the Sort() method is for every List(of ) / List<MyType>, you can use it.
You can do it this way is simple
private void SortDDL(ref DropDownList objDDL)
{
ArrayList textList = new ArrayList();
ArrayList valueList = new ArrayList();
foreach (ListItem li in objDDL.Items)
{
textList.Add(li.Text);
}
textList.Sort();
foreach (object item in textList)
{
string value = objDDL.Items.FindByText(item.ToString()).Value;
valueList.Add(value);
}
objDDL.Items.Clear();
for(int i = 0; i < textList.Count; i++)
{
ListItem objItem = new ListItem(textList[i].ToString(), valueList[i].ToString());
objDDL.Items.Add(objItem);
}
}
And call the method this SortDDL(ref yourDropDownList);
and that's it. The data in your dropdownlist will be sorted.
see http://www.codeproject.com/Articles/20131/Sorting-Dropdown-list-in-ASP-NET-using-C#
You can use this JavaScript function:
function sortlist(mylist)
{
var lb = document.getElementById(mylist);
arrTexts = new Array();
arrValues = new Array();
arrOldTexts = new Array();
for(i=0; i<lb.length; i++)
{
arrTexts[i] = lb.options[i].text;
arrValues[i] = lb.options[i].value;
arrOldTexts[i] = lb.options[i].text;
}
arrTexts.sort();
for(i=0; i<lb.length; i++)
{
lb.options[i].text = arrTexts[i];
for(j=0; j<lb.length; j++)
{
if (arrTexts[i] == arrOldTexts[j])
{
lb.options[i].value = arrValues[j];
j = lb.length;
}
}
}
}
Try This:
/// <summary>
/// AlphabetizeDropDownList alphabetizes a given dropdown list by it's displayed text.
/// </summary>
/// <param name="dropDownList">The drop down list you wish to modify.</param>
/// <remarks></remarks>
private void AlphabetizeDropDownList(ref DropDownList dropDownList)
{
//Create a datatable to sort the drop down list items
DataTable machineDescriptionsTable = new DataTable();
machineDescriptionsTable.Columns.Add("DescriptionCode", typeof(string));
machineDescriptionsTable.Columns.Add("UnitIDString", typeof(string));
machineDescriptionsTable.AcceptChanges();
//Put each of the list items into the datatable
foreach (ListItem currentDropDownListItem in dropDownList.Items) {
string currentDropDownUnitIDString = currentDropDownListItem.Value;
string currentDropDownDescriptionCode = currentDropDownListItem.Text;
DataRow currentDropDownDataRow = machineDescriptionsTable.NewRow();
currentDropDownDataRow["DescriptionCode"] = currentDropDownDescriptionCode.Trim();
currentDropDownDataRow["UnitIDString"] = currentDropDownUnitIDString.Trim();
machineDescriptionsTable.Rows.Add(currentDropDownDataRow);
machineDescriptionsTable.AcceptChanges();
}
//Sort the data table by description
DataView sortedView = new DataView(machineDescriptionsTable);
sortedView.Sort = "DescriptionCode";
machineDescriptionsTable = sortedView.ToTable();
//Clear the items in the original dropdown list
dropDownList.Items.Clear();
//Create a dummy list item at the top
ListItem dummyListItem = new ListItem(" ", "-1");
dropDownList.Items.Add(dummyListItem);
//Begin transferring over the items alphabetically from the copy to the intended drop
downlist
foreach (DataRow currentDataRow in machineDescriptionsTable.Rows) {
string currentDropDownValue = currentDataRow["UnitIDString"].ToString().Trim();
string currentDropDownText = currentDataRow["DescriptionCode"].ToString().Trim();
ListItem currentDropDownListItem = new ListItem(currentDropDownText, currentDropDownValue);
//Don't deal with dummy values in the list we are transferring over
if (!string.IsNullOrEmpty(currentDropDownText.Trim())) {
dropDownList.Items.Add(currentDropDownListItem);
}
}
}
This will take a given drop down list with a Text and a Value property of the list item and put them back into the given drop down list.
Best of Luck!
If you are adding options to the dropdown one by one without a dataset and you want to sort it later after adding items, here's a solution:
DataTable dtOptions = new DataTable();
DataColumn[] dcColumns = { new DataColumn("Text", Type.GetType("System.String")),
new DataColumn("Value", Type.GetType("System.String"))};
dtOptions.Columns.AddRange(dcColumns);
foreach (ListItem li in ddlOperation.Items)
{
DataRow dr = dtOptions.NewRow();
dr["Text"] = li.Text;
dr["Value"] = li.Value;
dtOptions.Rows.Add(dr);
}
DataView dv = dtOptions.DefaultView;
dv.Sort = "Text";
ddlOperation.Items.Clear();
ddlOperation.DataSource = dv;
ddlOperation.DataTextField = "Text";
ddlOperation.DataValueField = "Value";
ddlOperation.DataBind();
This would sort the dropdown items in alphabetical order.
If you are using a data bounded DropDownList, just go to the wizard and edit the bounding query by:
Goto the .aspx page (design view).
Click the magic Arrow ">"on the Dropdown List.
Select "Configure Data source".
Click Next.
On the right side of the opened window click "ORDER BY...".
You will have up two there field cariteria to sort by. Select the desired field and click OK, then click Finish.
You may not have access to the SQL, but if you have the DataSet or DataTable, you can certainly call the Sort() method.

Categories