I'm having a problem dynamically adding columns to a GridView. I need to change the layout -- i.e. the included columns -- based on the value in a DropDownList. When the user changes the selection in this list, I need to remove all but the first column and dynamically add additional columns based on the selection.
I have only one column defined in my markup -- column 0, a template column, in which I declare a Select link and another application specific LinkButton. That column needs to always be there. When the ListBoxSelection is made, I remove all but the first column and then re-add the desired columns (in this sample, I've simplified it to always add a "Title" column). Here is a portion of the code:
RemoveVariableColumnsFromGrid();
BoundField b = new BoundField();
b.DataField = "Title";
this.gvPrimaryListView.Columns.Add(b);
this.gvPrimaryListView.DataBind();
private void RemoveVariableColumnsFromGrid() {
int ColCount = this.gvPrimaryListView.Columns.Count;
//Leave column 0 -- our select and view template column
while (ColCount > 1) {
this.gvPrimaryListView.Columns.RemoveAt(ColCount - 1);
--ColCount;
}
}
The first time this code runs through, I see both the static column and the dynamically added "Title" column. However, the next time a selection is made, the first column is generated empty (nothing in it). I see the title column, and I see the first column to its left -- but there's nothing generated within it. In the debugger, I can see that gvPrimaryListView does indeed still have two columns and the first one (index 0) is indeed a template column. In fact, the column even retains it's width which is set as 165px in the markup below (for debugging purposes).
Any ideas?
<asp:GridView ID="gvPrimaryListView" runat="server" Width="100%" AutoGenerateColumns="false"
DataKeyNames="Document_ID" EnableViewState="true" DataSourceID="odsPrimaryDataSource"
AllowPaging="true" AllowSorting="true" PageSize="10" OnPageIndexChanging="activeListView_PageIndexChanging"
AutoGenerateSelectButton="False" OnSelectedIndexChanged="activeListView_SelectedIndexChanged"
Visible="true" OnRowDataBound="CtlDocList_RowDataBound" Font-Size="8pt" Font-Names="Helvetica">
<Columns>
<asp:TemplateField ShowHeader="false">
<ItemTemplate>
<asp:LinkButton EnableTheming="false" ID="CtlSelectDocRowBtn" runat="server" Text="Select"
CommandName="Select" CssClass="gridbutton" OnClick="RowSelectBtn_Click" />
<asp:ImageButton EnableTheming="false" ID="DocViewBtn" runat="server" ImageUrl="../../images/ViewDoc3.png"
CssClass="gridbutton" CommandName="Select" OnClick="DocViewBtn_Click" />
</ItemTemplate>
<ItemStyle Width="165px" />
</asp:TemplateField>
</Columns>
<EmptyDataTemplate>
<asp:Label ID="Label6" runat="server" Text="No rows found." SkinID="LabelHeader"></asp:Label>
</EmptyDataTemplate>
</asp:GridView>
Just some additional information.
It has nothing to do with the fact that it is the first column but everything to do with the fact that it is a TemplateField. If I put a normal column to the left (in the markup) and shift the TemplateField column to the right, the first column renders fine, and the (now second) TemplateField column disappears.
Another strange thing -- the problem doesn't happen the first postback -- OR THE SECOND -- but it starts on the third postback and then continues for subsequent postbacks. I'm stumped.
I recently conquered silmilar issues with dynamic columns in gridviews, perhaps this will help.
First turn the viewstate off
Second add the columns programatically in a function fired in the oninit event
Lastly I used the following helper class to cause the checkboxes to instantiate when the RowDataBound event kicked off. Yes some of it is hard coded.
Heck here is all the code. Have at it :) Warrenty as is, blah blah blah...
Finally since I am just getting my feet wet DotNet any tips would be appreciated [IE don't rip me too much :) ]. And yes 'borrowed' the initial code from the web somewhere, sorry I cant remember off the top of my head :(
-- Fire this off in protected override void OnInit
private void GridViewProject_AddColumns()
{
DataSet dsDataSet = new DataSet();
TemplateField templateField = null;
try
{
StoredProcedure sp = new StoredProcedure("ExpenseReportItemType_GetList", "INTRANETWEBDB", Context.User.Identity.Name);
dsDataSet = sp.GetDataSet();
if (sp.RC != 0 && sp.RC != 3000)
{
labelMessage.Text = sp.ErrorMessage;
}
int iIndex = 0;
int iCount = dsDataSet.Tables[0].Rows.Count;
string strCategoryID = "";
string strCategoryName = "";
iStaticColumnCount = GridViewProject.Columns.Count;
// Insert all columns immediatly to the left of the LAST column
while (iIndex < iCount)
{
strCategoryName = dsDataSet.Tables[0].Rows[iIndex]["CategoryName"].ToString();
strCategoryID = dsDataSet.Tables[0].Rows[iIndex]["CategoryID"].ToString();
templateField = new TemplateField();
templateField.HeaderTemplate = new GridViewTemplateExternal(DataControlRowType.Header, strCategoryName, strCategoryID);
templateField.ItemTemplate = new GridViewTemplateExternal(DataControlRowType.DataRow, strCategoryName, strCategoryID);
templateField.FooterTemplate = new GridViewTemplateExternal(DataControlRowType.Footer, strCategoryName, strCategoryID);
// Have to decriment iStaticColumnCount to insert dynamic columns BEFORE the edit row
GridViewProject.Columns.Insert((iIndex + (iStaticColumnCount-1)), templateField);
iIndex++;
}
iFinalColumnCount = GridViewProject.Columns.Count;
iERPEditColumnIndex = (iFinalColumnCount - 1); // iIndex is zero based, Count is not
}
catch (Exception exception)
{
labelMessage.Text = exception.Message;
}
}
-- Helper Class
public class GridViewTemplateExternal : System.Web.UI.ITemplate
{
#region Fields
public DataControlRowType DataRowType;
private string strCategoryID;
private string strColumnName;
#endregion
#region Constructor
public GridViewTemplateExternal(DataControlRowType type, string ColumnName, string CategoryID)
{
DataRowType = type; // Header, DataRow,
strColumnName = ColumnName; // Header name
strCategoryID = CategoryID;
}
#endregion
#region Methods
public void InstantiateIn(System.Web.UI.Control container)
{
switch (DataRowType)
{
case DataControlRowType.Header:
// build the header for this column
Label labelHeader = new Label();
labelHeader.Text = "<b>" + strColumnName + "</b>";
// All CheckBoxes "Look Up" to the header row for this information
labelHeader.Attributes["ERICategoryID"] = strCategoryID;
labelHeader.Style["writing-mode"] = "tb-rl";
labelHeader.Style["filter"] = "flipv fliph";
container.Controls.Add(labelHeader);
break;
case DataControlRowType.DataRow:
CheckBox checkboxAllowedRow = new CheckBox();
checkboxAllowedRow.Enabled = false;
checkboxAllowedRow.DataBinding += new EventHandler(this.CheckBox_DataBinding);
container.Controls.Add(checkboxAllowedRow);
break;
case DataControlRowType.Footer:
// No data handling for the footer addition row
CheckBox checkboxAllowedFooter = new CheckBox();
container.Controls.Add(checkboxAllowedFooter);
break;
default:
break;
}
}
public void CheckBox_DataBinding(Object sender, EventArgs e)
{
CheckBox checkboxAllowed = (CheckBox)sender;// get the control that raised this event
GridViewRow row = (GridViewRow)checkboxAllowed.NamingContainer;// get the containing row
string RawValue = DataBinder.Eval(row.DataItem, strColumnName).ToString();
if (RawValue.ToUpper() == "TRUE")
{
checkboxAllowed.Checked = true;
}
else
{
checkboxAllowed.Checked = false;
}
}
#endregion
}
best solution for add dynamic column to grid view (ASP) placed on code project by below address :
please check it out :
http://www.codeproject.com/Articles/13461/how-to-create-columns-dynamically-in-a-grid-view
diningphilanderer.myopenid.com has a similar approach to what I would recommend.
The problem is that you have to rebind the grid each time a postback occurs and consequently you have to rebuild the columns. I like to have a method called BindGrid() that first clears the Columns GridView1.Columns.Clear(); then adds them programatically, then sets the datasource and calls databind. Make sure you have viewstate disabled for the grid and you have autogeneratecolumns = false;
I found this earlier today: TemplateField in a GridView doesn't have its ViewState restored when BoundFields are inserted.
Looks like a bug that Microsoft doesn't plan on fixing, so you'll have to try one of the solutions above. I'm having the same problem -- I have some DataBoundFields and some TemplateFields, and after a postback, the TemplateField based columns lose their controls and data.
I have written a short article on the similar topic that deal with dynamically populating GridView column based on the columns selected by the user in the CheckBoxList control. Hope this will help to those looking for simple demonstration How to generate GridView columns dynamically based on user selection?.
void Page_PreRenderComplete(object sender, EventArgs e)
{
// TemplateField reorder bug: if there is a TemplateField based column (or derived therefrom), GridView may blank out
// the column (plus possibly others) during any postback, if the user has moved it from its original markup position.
// This is probably a viewstate bug, as it happens only if a TemplateField based column has been moved. The workaround is
// to force a databind before each response. See https://connect.microsoft.com/VisualStudio/feedback/details/104994/templatefield-in-a-gridview-doesnt-have-its-viewstate-restored-when-boundfields-are-inserted
//
// This problem is also happening for grid views inside a TabPanel, even if the TemplateField based columns have not
// been moved. Also do a databind in that case.
//
// We also force a databind right after the user has submitted the column chooser dialog.
// (This is because the user could have moved TemplateField based column(s) but ColChooserHasMovedTemplateFields()
// returns false -- ie when the user has moved all TemplateField based columns back to their original positions.
if ((!_DataBindingDone && (ColChooserHasMovedTemplateFields() || _InTabPanel)) || _ColChooserPanelSubmitted || _ColChooserPanelCancelled)
DataBind();
// There is a problem with the GridView in case of custom paging (which is true here) that if we are on the last page,
// and we delete all row(s) of that page, GridView is not aware of the deletion during the subsequent data binding,
// will ask the ODS for the last page of data, and will display a blank. By PreRenderComplete, it will somehow have
// realized that its PageIndex, PageCount, etc. are too big and updated them properly, but this is too late
// as the data binding has already occurred with oudated page variables. So, if we were on the last page just before
// the last data binding (_LastPageIndex == _LastPageCount - 1) and PageIndex was decremented after the data binding,
// we know this scenario has happened and we redo the data binding. See http://scottonwriting.net/sowblog/archive/2006/05/30/163173.aspx
// for a discussion of the problem when the GridView uses the ODS to delete data. The discussion also applies when we
// delete data directly through ClassBuilder objects.
if (_LastPageIndex == _LastPageCount - 1 && PageIndex < _LastPageIndex)
DataBind();
if (EnableColChooser)
{
if (!_IsColChooserApplied)
ApplyColChooser(null, false, false);
else
{
// The purpose of calling ApplyColChooser() here is to order the column headers properly. The GridView
// at this point will have reverted the column headers to their original order regardless of ViewState,
// so we need to apply our own ordering. (This is not true of data cells, so we don't have to apply
// ordering to them, as reflected by the parameters of the call.)
// If we have already processed column reordering upon the column chooser panel being submitted,
// don't repeat the operation.
if (!_ColChooserPanelSubmitted)
ApplyColChooser(null, false, true);
}
}
}
I found this little nugget in the documentation, under the DataControlFieldCollection Class.
If you are using the GridView or DetailsView control, the DataControlField objects that are automatically created (for example, when the AutoGenerateColumns property is true) are not stored in the publicly accessible fields collection. You can only access and manipulate DataControlField objects that are not automatically generated.
I guess the answer is to do all of your column manipulation in code, and then your approach should work fine.
Instead of dynamically adding columns, could you define them at the outset and hide/show them as needed (either with Visible="false" or setting the CssClass of the control/header/footer to a class with "display: none;")? I use this method in some of my code, including template columns, with no issues.
Sorry, Decker. I missed a few key points obviously.. :)
If this is still a problem for you, I wonder if it makes a difference what you have in your item template? If you just put some text in there, then refresh the page a few times, does the text appear on the first load, then not on the second?
Also, when the problem arises is there any html markup at all in the cells or are they completely empty?
Related
Seems to be easy but I am having a hard time with this.
<asp:TemplateField HeaderText="ID" InsertVisible="False" SortExpression="id">
<ItemTemplate>
<%#Eval("Id")%>
</ItemTemplate>
</asp:TemplateField>
There is a button in the last column of gridview. Click this button updated the database and refreshed gridview. It also look at the id column in gridview and tries to highlight the row that was edited.
The code works without any problem if ID field is bounded field and is not a URL. But when it is a URL, I cannot seem to read the text value of the URL. I have tried various solution (help from SO and online)
HyperLink link = (HyperLink)row.FindControl("id"); // did not work
((HyperLink)GridView1.Rows[i].Cells[0].Controls[0]).Text // did not work
This is the code snippet that I need help with
for (int i = 0; i < GridView1.Rows.Count; i++)
{
GridViewRow row;
row = GridView1.Rows[i];
if (row.RowType == DataControlRowType.DataRow)
{
HyperLink link = (HyperLink)row.FindControl("id");
if (((HyperLink)GridView1.Rows[i].Cells[0].Controls[0]).Text == button.CommandName)
{
row.BackColor = System.Drawing.Color.IndianRed;
}
}
}
I am using button.CommandName to store the ID field which works fine. I just can't seem to find the hyperlink control in the gridview inside a template field.
I am getting the following error which does not make sense to me
Unable to cast object of type 'System.Web.UI.DataBoundLiteralControl'
to type 'System.Web.UI.WebControls.HyperLink'.
Update1
This code works without hitch, if I do not use hyperlink field.
for (int i = 0; i < GridView1.Rows.Count; i++)
{
GridViewRow row;
row = GridView1.Rows[i];
if (row.Cells[0].Text.Equals(button.CommandName))
{
row.BackColor = System.Drawing.Color.IndianRed;
}
}
If change the column 0 to hyperlink and change the code corresponding, then it does not work. Clearly reading the wrong cell is not the problem.
for (int i = 0; i < GridView1.Rows.Count; i++)
{
GridViewRow row;
row = GridView1.Rows[i];
HtmlAnchor anchor = (HtmlAnchor) row.Cells[0].Controls[0];
if ( anchor.InnerText.Equals(button.CommandName))
{
row.BackColor = System.Drawing.Color.IndianRed;
}
}
First things first - you are trying to FindControl("id"); where your control in the design view is actually ID - Case matters.
Another thing - this also appears to be because <a> isn't actually a HyperLink control, but actually a HtmlGenericControl - thus trying to cast your control is resulting in nothing.
You could do one of two things - change your code-behind to get HtmlGenericControl link = (HtmlGenericControl )row.FindControl("ID");
Or change your design view and use an <asp:Hyperlink> control instead of the HTML <a>
Your error Unable to cast object of type 'System.Web.UI.DataBoundLiteralControl' (which is ain HTML terms) to type 'System.Web.UI.WebControls.HyperLink'.
Is saying ((HyperLink)GridView1.Rows[i].Cells[0].Controls[0]
that the control at position 0 in the first cell on the row your processing is a literal and NOT a link. You can try to fudge it by looking at Controls[1] instead.
you can view the rendered HTML of your table and verify this - your link will be nested in a span, or next to a span..
Examine the Controls in debug and see what is actually contained in it.
Update
There is a lot of confusion over HOW your calling your code. You have e.Row.RowType which leads me to believe you're doing this in RowDataBound.
If this is the case then you do NOT need to loop through all of your gridview rows as this method gets called on every row - so you would be calling each row, then each row in the grid.. MASSIVE amount of looping going on for a big grid.
So try this instead - it is only interested on that one row.
also - not sure where you;re getting your button.CommandName from
For this you will need to examine your FindControl method to make sure it actually IS a hyperlink control
if ((e.Row.RowType == DataControlRowType.DataRow)) {
GridViewRow row = e.Row;
// get your link - if indeed the control IS a hyperlink
// this will be null if the control "id" is NOT a hyperlink control
HyperLink link = (HyperLink)row.FindControl("id");
if ((link.Text == Button.CommandName)) {
row.BackColor = Drawing.Color.IndianRed;
}
}
last update...
Ok - after more comments I reckon you need to recursively search for the control. this is because FindControl will only look at the direct controls within a control. it will not find controls within controls within your control - I.E FindControl looks at the first children only and not grandchildren.
So create this method where ever you like:
public static Control FindControlRecursive(Control Root, string Id)
{
if (Root.ID == Id) { return Root; }
foreach (Control Ctl in Root.Controls)
{
Control FoundCtl = FindControlRecursive(Ctl, Id);
if (FoundCtl != null) { return FoundCtl; }
}
return null;
}
Then pass in your row and the ID of the control you're looking for.
So like this - change:
HyperLink link = (HyperLink)row.FindControl("id");
to this - notice i kept your lowercase id - not sure if you are using lowercase or uppercase - this method will hunt out the little bugger for you :)
Control link = FindControlRecursive(row, "id");
Once you have your control you can cast it to what you need/or it should be
I'm trying to implement Nick Wesselman's Dynamic Place Holder technique in Sitecore. I'm using sitecore 6.5 and asp.net.
http://www.techphoria414.com/Blog/2011/August/Dynamic_Placeholder_Keys_Prototype
http://www.techphoria414.com/Blog/2012/May/Sitecore_Page_Editor_Unleashed
I used the sourcecode I Found in the Sitecore_Page_Editor_Unleashed BLOG
All the pipelines seem to be in place and working. But in the Dynamic Placeholder control the following bit of code returns 0 (zero) although there are five dynamic placeholders on the control
Stack<Placeholder> stack = Switcher<Placeholder, PlaceholderSwitcher>.GetStack(false);
To Isolate the problem I created a very simple sitecore instance. 1 layout and 1 sublayout.
In the codebehind sublayout I have the following code for demo purposes:
var list = new List<int>();
for (int i = 0; i < 5; i++)
{
list.Add(i);
}
Repeater.DataSource = list;
DataBind();
This is the source of the ascx/sublayout
<asp:Repeater runat="server" ID="Repeater">
<ItemTemplate>
<mi:DynamicKeyPlaceholder runat="server" ID="pl" Key="place"></mi:DynamicKeyPlaceholder>
</ItemTemplate>
</asp:Repeater>
Result is that all five placeholders still have the same key.
What to do?
I've never tested this solution with multiple dynamically created placeholder controls inside the same sublayout. It's designed to solve the problem of the same sublayout (with a placeholder) being placed on a page, multiple times. It works by grabbing the ID of the containing rendering and appending it to the placeholder key. Steps I would take:
Ensure that the sublayout containing your repeater is placed in the layout dynamically, through a placeholder. You should not be using <sc:Sublayout/> to put the sublayout on the page. This may explain why the stack is empty.
You will also need to databind the "Key" field on the DynamicKeyPlaceholder. Within the same sublayout, all the DynamicKeyPlaceholder controls need to have a unique Key.
Of course, the danger here is that if the data driving your repeater changes, the Key could change. You might consider re-evaluating your architecture and driving it based on placing the same sublayout multiple times (with datasources), instead of a repeater.
What I have done is similar what you are requesting...I created a reference of another sublayout (which implements dynamic placeholders) from the calling control (which want to have dynamic ph).
So suppose my calling control is ControlA and implementing control is ControlB.
This is the markup of ControlA:
<ControlB ID="SectionItems" runat="server" CurrentItem="<%# Container.DataItem %>" />
And this is the code behind for it:
private static void SetIndexForControlBItems(RepeaterItemEventArgs e)
{
var controlBItems = e.Item.FindControl("ControlB") as ControlB;
if (controlBItems != null)
controlBItems.PropertyName = e.Item.ItemIndex.ToString();
}
When you assign the property name (which is going to be present in ControlB) then you will get the value of which index you are assigning dynamic PH to. And in ControlB you can do something like this:
private void SetPlaceholderKeys(RepeaterItemEventArgs e)
{
Placeholder phPreColumnContentTopLeft = e.Item.FindControl("phColumnContentTopLeft") as Placeholder;
if (phPreColumnContentTopLeft != null)
phPreColumnContentTopLeft.Key = "topLeftColumnSectionItems" + e.Item.ItemIndex + PropertyName;
Hope this helps!
I am currently facing a problem. How to get the latest selected value from a asp.net checkbox list?
From looping through the Items of a checkbox list, I can get the highest selected index and its value, but it is not expected that the user will select the checkbox sequentially from lower to higher index. So, how to handle that?
Is there any event capturing system that will help me to identify the exact list item which generates the event?
If I understood it right, this is the code I'd use:
protected void CheckBoxList1_SelectedIndexChanged(object sender, EventArgs e)
{
int lastSelectedIndex = 0;
string lastSelectedValue = string.Empty;
foreach (ListItem listitem in CheckBoxList1.Items)
{
if (listitem.Selected)
{
int thisIndex = CheckBoxList1.Items.IndexOf(listitem);
if (lastSelectedIndex < thisIndex)
{
lastSelectedIndex = thisIndex;
lastSelectedValue = listitem.Value;
}
}
}
}
Is there any event capturing system that will help me to identify the exact list item which generates the event?
You use the event CheckBoxList1_SelectedIndexChanged of the CheckBoxList. When a CheckBox of the list is clicked this event is called and then you can check whatever condition you want.
Edit:
The following code allows you to get the last checkbox index that the user selected. With this data you can get the last selected value by the user.
protected void CheckBoxList1_SelectedIndexChanged(object sender, EventArgs e)
{
string value = string.Empty;
string result = Request.Form["__EVENTTARGET"];
string[] checkedBox = result.Split('$'); ;
int index = int.Parse(checkedBox[checkedBox.Length - 1]);
if (CheckBoxList1.Items[index].Selected)
{
value = CheckBoxList1.Items[index].Value;
}
else
{
}
}
Below is the code which gives you the Latest selected CheckBoxList Item.
string result = Request.Form["__EVENTTARGET"];
string [] checkedBox = result.Split('$'); ;
int index = int.Parse(checkedBox[checkedBox.Length - 1]);
if (cbYears.Items[index].Selected)
{
//your logic
}
else
{
//your logic
}
Hope this helps.
Don't know about you, but as a user i wouldn't want the page to post back every time a checkbox item was checked.
This is the solution i would go with (jQuery):
Declare a server-side hidden field on your form:
<asp:HiddenField ID="HiddenField1" runat="server" EnableViewState="true" />
Then wire up client-side event handlers for the checkboxes to store checkbox clicked:
$('.someclassforyourcheckboxes').click(function() {
$('#HiddenField1').val($(this).attr('id'));
This is a lightweight mechanism for storing the ID of the "latest" checkbox clicked. And you won't have to set autopostback=true for the checkboxes and do an unecessary postback.
You dont HAVE to use jQuery - you can use regular Javascript, but, why do more work? =)
Then when you actually do the postback (on a submit button click i assume), just check the value of the hidden field.
Unless of course you WANT to postback on every checkbox click, but i can't envision a scenario in which you'd want this (maybe you're using UpdatePanel).
EDIT
The HTML of a checkbox list looks like this:
<input type="checkbox" name="vehicle" value="Bike" /> I have a bike
So, you can access three things:
Vehicle = $(this).attr('name');
Bike = $(this).attr('value');
I have a bike = $(this).html();
If you're trying to access the databound value, try the second technique.
Give that a try.
I am dynamically binding a typed list to a GridView control.
The Grid View Control is in an asp.net page that is wrapped in an asp:UpdatePanel (Ajax).
The first column contains a checkbox control.
Only one checkbox may be checked in this column.
If the user checks a checkbox, all other checkbox must be unchecked.
I am trying to achieve this using client-side script without success.
In the handler for the GridView’s RowDatabound event, have attempted to add an attribute to the CheckBox contained within the cell.
protected void ErrorGridView_RowDatabound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if(e.Row.Cells[0].HasControls())
{
foreach (var control in e.Row.Cells[0].Controls)
{
if (!(control is CheckBox)) continue;
var checkBox = (CheckBox)control;
checkBox.Attributes.Add("CheckedChanged", "errorCheckChanged");
return;
}
}
}
The client side script is registered on the Page_Load event handler - as below:
if (!Page.ClientScript.IsClientScriptBlockRegistered("ErrorsCheckBoxHandler"))
Page.ClientScript.RegisterClientScriptBlock(GetType(),"ErrorsCheckBoxHandler", "function errorCheckChanged() {window.alert(\"here\"); }");
The problem is that the function is not called when any checkboxes are clicked. Hopefully someone can shed some light as to what am I missing here?
Also, what would be the best way to perform the de-selection of the any other checkboxes that are checked in the target column?
My plan would be to change the 'errorCheckChanged' function to take one parameter (the checkbox object). I would change the above code; adding to the attribute addition signature:
checkBox.Attributes.Add("CheckedChanged", "errorCheckChanged(this)");
Hopefully, I will then be able to:
(1) determine if the checkbox state is 'checked'. (If it is 'checked', then continue below steps)
(2) find the checkbox parent (= cell) and then determine the affected GridView Row.
(3) Loop through all rows setting the checkboxes to 'Checked=false' except of the current row.
Would this be considered the right approach?
Thanks
Grant
You can also add the onclick event of checkbox in design time.
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:CheckBox ID="chkSelect" onclick="errorCheckChanged(this)" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
And the JavaScript looks like
function errorCheckChanged(chkBox){
var gridView = document.getElementById('<% =GridView1.ClientID %>');
var Elements = gridView.getElementsByTagName('input');
for(var i = 0; i < Elements.length; i++){
if(Elements[i].type == 'checkbox' && Elements[i].id != chkBox.id && chkBox.checked)
Elements[i].checked = false;
}
}
use the onclick attribute rather than CheckChanged. i don't think that's a valid js event. so
checkBox.Attributes.Add("onclick", "errorCheckChanged(this);");
to get a list of checkboxes you can do
js:
var grid = document.getElementById('<% =GridView1.ClientID %>');
var checks = grid.getElementsByTagName('input');
you'll have to check the type attribute to make sure it's a checkbox, or you can give all the checkboxes a specific class to logically group them. anyway you can check your clicked element id against the list.
I have a dropdownlist, which dynamically populate data from SQL Server and i wanna manually insert two items on top of the DDL after data binding. So, the DDL would has data something like this:
Select Branch (manually insert)
ALL (manually insert)
AIR
AMP
ABG
...
I tried to achieve it by using code below:
ddlBranch.Items.Insert(0, "Select Branch")
ddlBranch.Items(0).Value = CMM.sExcVal1
ddlBranch.Items.Insert(1, "ALL")
ddlBranch.Items(1).Value = "ALL"
but it comes out giving me the data like this:
Select Branch (manually insert)
ALL (manually insert)
('AIR' branch should be here but it's gone)
AMP
ABG
...
After manually insert the 'ALL' item into the DDL, the 'AIR' is gone which is already replaced by the 'ALL'. How can i remain all the data from server and at the same time i can manually insert two items?
It is much simpler than you think. All you need to do is change the html code as below:
<asp:DropDownList ID="dropdownlist1" runat="server" AppendDataBoundItems="true">
<asp:ListItem>Select Branch</asp:ListItem>
<asp:ListItem>ALL</asp:ListItem>
</asp:DropDownList>
The important thing is the AppendDataBoundItems="true" bit, which will append the remaining items that will be brought back from the SQL Server as normal (however you did it) after the two entries you manually typed in.
Hope that helps.
Ash (UK).
Just skip the automatic databinding.
if (!IsPostBack)
{
list.Items.Clear();
list.Items.Add(new ListItem("Select branch", ""));
list.Items.Add(new ListItem("ALL", "*");
// ----- Just bind your items here from the DB.
foreach (var item in yourCollection)
{
ListItem li = new ListItem(item.Text, item.Value);
list.Items.Add(li);
}
}
Alternatively, if you need this placeholder item in a lot of places in your app - you might want to create a Component that inherits from DropDownList. Then, override the DataBind method -
public override void DataBind()
{
base.DataBind();
ListItem li = new ListItem { Value = String.Empty, Text = "[Select an item ...]" };
this.Items.Insert(0, li);
}